Ejemplo n.º 1
0
    def parse_uri(self, uri):
        prefix = "rbd://"
        if not uri.startswith(prefix):
            reason = _("URI must start with rbd://")
            msg = _LI("Invalid URI: %s") % reason

            LOG.info(msg)
            raise exceptions.BadStoreUri(message=reason)
        # convert to ascii since librbd doesn't handle unicode
        try:
            ascii_uri = str(uri)
        except UnicodeError:
            reason = _("URI contains non-ascii characters")
            msg = _LI("Invalid URI: %s") % reason

            LOG.info(msg)
            raise exceptions.BadStoreUri(message=reason)
        pieces = ascii_uri[len(prefix) :].split("/")
        if len(pieces) == 1:
            self.fsid, self.pool, self.image, self.snapshot = (None, None, pieces[0], None)
        elif len(pieces) == 4:
            self.fsid, self.pool, self.image, self.snapshot = map(urllib.unquote, pieces)
        else:
            reason = _("URI must have exactly 1 or 4 components")
            msg = _LI("Invalid URI: %s") % reason

            LOG.info(msg)
            raise exceptions.BadStoreUri(message=reason)
        if any(map(lambda p: p == "", pieces)):
            reason = _("URI cannot contain empty components")
            msg = _LI("Invalid URI: %s") % reason

            LOG.info(msg)
            raise exceptions.BadStoreUri(message=reason)
Ejemplo n.º 2
0
    def add(self, image_id, image_file, image_size, context=None):
        """
        Stores an image file with supplied identifier to the backend
        storage system and returns a tuple containing information
        about the stored image.

        :param image_id: The opaque image identifier
        :param image_file: The image data to write, as a file-like object
        :param image_size: The size of the image data to write, in bytes

        :retval tuple of URL in backing store, bytes written, checksum
                and a dictionary with storage system specific information
        :raises `glance_store.exceptions.Duplicate` if the image already
                existed

        S3 writes the image data using the scheme:
            s3://<ACCESS_KEY>:<SECRET_KEY>@<S3_URL>/<BUCKET>/<OBJ>
        where:
            <USER> = ``s3_store_user``
            <KEY> = ``s3_store_key``
            <S3_HOST> = ``s3_store_host``
            <BUCKET> = ``s3_store_bucket``
            <ID> = The id of the image being added
        """
        loc = StoreLocation(
            {
                "scheme": self.scheme,
                "bucket": self.bucket,
                "key": image_id,
                "s3serviceurl": self.full_s3_host,
                "accesskey": self.access_key,
                "secretkey": self.secret_key,
            },
            self.conf,
        )

        s3_conn = self._create_connection(loc)

        create_bucket_if_missing(self.conf, self.bucket, s3_conn)

        bucket_obj = get_bucket(s3_conn, self.bucket)
        obj_name = str(image_id)
        key = bucket_obj.get_key(obj_name)
        if key and key.exists():
            raise exceptions.Duplicate(
                message=_("S3 already has an image at " "location %s") % self._sanitize(loc.get_uri())
            )

        msg = _(
            "Adding image object to S3 using (s3_host=%(s3_host)s, "
            "access_key=%(access_key)s, bucket=%(bucket)s, "
            "key=%(obj_name)s)"
        ) % ({"s3_host": self.s3_host, "access_key": self.access_key, "bucket": self.bucket, "obj_name": obj_name})
        LOG.debug(msg)
        LOG.debug("Uploading an image file to S3 for %s" % self._sanitize(loc.get_uri()))

        if image_size < self.s3_store_large_object_size:
            return self.add_singlepart(image_file, bucket_obj, obj_name, loc)
        else:
            return self.add_multipart(image_file, image_size, bucket_obj, obj_name, loc)
Ejemplo n.º 3
0
    def get_size(self, location, context=None):
        """
        Takes a `glance_store.location.Location` object that indicates
        where to find the image file and returns the image size

        :param location `glance_store.location.Location` object, supplied
                        from glance_store.location.get_location_from_uri()
        :raises `glance_store.exceptions.NotFound` if image does not exist
        :rtype int
        """

        loc = location.store_location

        try:
            self._check_context(context)
            volume = get_cinderclient(self.conf,
                                      context).volumes.get(loc.volume_id)
            # GB unit convert to byte
            return volume.size * (1024 ** 3)
        except cinder_exception.NotFound as e:
            reason = _("Failed to get image size due to "
                       "volume can not be found: %s") % self.volume_id
            LOG.error(reason)
            raise exceptions.NotFound(reason)
        except Exception as e:
            LOG.exception(_("Failed to get image size due to "
                            "internal error: %s") % e)
            return 0
Ejemplo n.º 4
0
    def _sanity_check(self):
        if self.conf.glance_store.vmware_api_retry_count <= 0:
            msg = _('vmware_api_retry_count should be greater than zero')
            LOG.error(msg)
            raise exceptions.BadStoreConfiguration(
                store_name='vmware_datastore', reason=msg)

        if self.conf.glance_store.vmware_task_poll_interval <= 0:
            msg = _('vmware_task_poll_interval should be greater than zero')
            LOG.error(msg)
            raise exceptions.BadStoreConfiguration(
                store_name='vmware_datastore', reason=msg)

        if not (self.conf.glance_store.vmware_datastore_name
                or self.conf.glance_store.vmware_datastores):
            msg = (_("Specify at least 'vmware_datastore_name' or "
                     "'vmware_datastores' option"))
            LOG.error(msg)
            raise exceptions.BadStoreConfiguration(
                store_name='vmware_datastore', reason=msg)

        if (self.conf.glance_store.vmware_datastore_name and
                self.conf.glance_store.vmware_datastores):
            msg = (_("Specify either 'vmware_datastore_name' or "
                     "'vmware_datastores' option"))
            LOG.error(msg)
            raise exceptions.BadStoreConfiguration(
                store_name='vmware_datastore', reason=msg)
Ejemplo n.º 5
0
    def get(self, location, offset=0, chunk_size=None, context=None):
        """
        Takes a `glance_store.location.Location` object that indicates
        where to find the image file, and returns a tuple of generator
        (for reading the image file) and image_size

        :param location `glance_store.location.Location` object, supplied
                        from glance_store.location.get_location_from_uri()
        :param offset: offset to start reading
        :param chunk_size: size to read, or None to get all the image
        :param context: Request context
        :raises `glance_store.exceptions.NotFound` if image does not exist
        """

        loc = location.store_location
        self._check_context(context)
        try:
            client = get_cinderclient(self.conf, context)
            volume = client.volumes.get(loc.volume_id)
            size = int(volume.metadata.get('image_size',
                                           volume.size * units.Gi))
            iterator = self._cinder_volume_data_iterator(
                client, volume, size, offset=offset,
                chunk_size=self.READ_CHUNKSIZE, partial_length=chunk_size)
            return (iterator, chunk_size or size)
        except cinder_exception.NotFound:
            reason = _("Failed to get image size due to "
                       "volume can not be found: %s") % volume.id
            LOG.error(reason)
            raise exceptions.NotFound(reason)
        except cinder_exception.ClientException as e:
            msg = (_('Failed to get image volume %(volume_id): %(error)s')
                   % {'volume_id': loc.volume_id, 'error': e})
            LOG.error(msg)
            raise exceptions.BackendException(msg)
Ejemplo n.º 6
0
    def _delete_image(self, image_name, snapshot_name=None, context=None):
        """
        Delete RBD image and snapshot.

        :param image_name Image's name
        :param snapshot_name Image snapshot's name

        :raises NotFound if image does not exist;
                InUseByStore if image is in use or snapshot unprotect failed
        """
        with rados.Rados(conffile=self.conf_file, rados_id=self.user) as conn:
            with conn.open_ioctx(self.pool) as ioctx:
                try:
                    # First remove snapshot.
                    if snapshot_name is not None:
                        with rbd.Image(ioctx, image_name) as image:
                            try:
                                image.unprotect_snap(snapshot_name)
                            except rbd.ImageBusy:
                                log_msg = _(
                                    "snapshot %(image)s@%(snap)s " "could not be unprotected because " "it is in use"
                                )
                                LOG.debug(log_msg % {"image": image_name, "snap": snapshot_name})
                                raise exceptions.InUseByStore()
                            image.remove_snap(snapshot_name)

                    # Then delete image.
                    rbd.RBD().remove(ioctx, image_name)
                except rbd.ImageNotFound:
                    raise exceptions.NotFound(message=_("RBD image %s does not exist") % image_name)
                except rbd.ImageBusy:
                    log_msg = _("image %s could not be removed " "because it is in use")
                    LOG.debug(log_msg % image_name)
                    raise exceptions.InUseByStore()
Ejemplo n.º 7
0
    def parse_uri(self, uri):
        prefix = 'rbd://'
        self.validate_schemas(uri, valid_schemas=(prefix,))
        # convert to ascii since librbd doesn't handle unicode
        try:
            ascii_uri = str(uri)
        except UnicodeError:
            reason = _('URI contains non-ascii characters')
            msg = _LI("Invalid URI: %s") % reason

            LOG.info(msg)
            raise exceptions.BadStoreUri(message=reason)
        pieces = ascii_uri[len(prefix):].split('/')
        if len(pieces) == 1:
            self.fsid, self.pool, self.image, self.snapshot = \
                (None, None, pieces[0], None)
        elif len(pieces) == 4:
            self.fsid, self.pool, self.image, self.snapshot = \
                map(urllib.parse.unquote, pieces)
        else:
            reason = _('URI must have exactly 1 or 4 components')
            msg = _LI("Invalid URI: %s") % reason

            LOG.info(msg)
            raise exceptions.BadStoreUri(message=reason)
        if any(map(lambda p: p == '', pieces)):
            reason = _('URI cannot contain empty components')
            msg = _LI("Invalid URI: %s") % reason

            LOG.info(msg)
            raise exceptions.BadStoreUri(message=reason)
Ejemplo n.º 8
0
    def _wait_volume_status(self, volume, status_transition, status_expected):
        max_recheck_wait = 15
        timeout = self.conf.glance_store.cinder_state_transition_timeout
        volume = volume.manager.get(volume.id)
        tries = 0
        elapsed = 0
        while volume.status == status_transition:
            if elapsed >= timeout:
                msg = (_('Timeout while waiting while volume %(volume_id)s '
                         'status is %(status)s.')
                       % {'volume_id': volume.id, 'status': status_transition})
                LOG.error(msg)
                raise exceptions.BackendException(msg)

            wait = min(0.5 * 2 ** tries, max_recheck_wait)
            time.sleep(wait)
            tries += 1
            elapsed += wait
            volume = volume.manager.get(volume.id)
        if volume.status != status_expected:
            msg = (_('The status of volume %(volume_id)s is unexpected: '
                     'status = %(status)s, expected = %(expected)s.')
                   % {'volume_id': volume.id, 'status': volume.status,
                      'expected': status_expected})
            LOG.error(msg)
            raise exceptions.BackendException(msg)
        return volume
Ejemplo n.º 9
0
 def _load_config(self):
     try:
         scf = self.conf.glance_store.swift_store_config_file
         conf_file = self.conf.find_file(scf)
         CONFIG.read(conf_file)
     except Exception as e:
         msg = (i18n._("swift config file "
                       "%(conf)s:%(exc)s not found") %
                {'conf': self.conf.glance_store.swift_store_config_file,
                 'exc': e})
         LOG.error(msg)
         raise exceptions.BadStoreConfiguration(store_name='swift',
                                                reason=msg)
     account_params = {}
     account_references = CONFIG.sections()
     for ref in account_references:
         reference = {}
         try:
             reference['auth_address'] = CONFIG.get(ref, 'auth_address')
             reference['user'] = CONFIG.get(ref, 'user')
             reference['key'] = CONFIG.get(ref, 'key')
             account_params[ref] = reference
         except (ValueError, SyntaxError, configparser.NoOptionError) as e:
             LOG.exception(i18n._("Invalid format of swift store config"
                                  "cfg"))
     return account_params
Ejemplo n.º 10
0
def store_add_to_backend(image_id, data, size, store, context=None):
    """
    A wrapper around a call to each stores add() method.  This gives glance
    a common place to check the output

    :param image_id:  The image add to which data is added
    :param data: The data to be stored
    :param size: The length of the data in bytes
    :param store: The store to which the data is being added
    :return: The url location of the file,
             the size amount of data,
             the checksum of the data
             the storage systems metadata dictionary for the location
    """
    (location, size, checksum, metadata) = store.add(image_id, data, size)
    if metadata is not None:
        if not isinstance(metadata, dict):
            msg = (_("The storage driver %(driver)s returned invalid "
                     " metadata %(metadata)s. This must be a dictionary type")
                   % dict(driver=str(store), metadata=str(metadata)))
            LOG.error(msg)
            raise exceptions.BackendException(msg)
        try:
            check_location_metadata(metadata)
        except exceptions.BackendException as e:
            e_msg = (_("A bad metadata structure was returned from the "
                       "%(driver)s storage driver: %(metadata)s.  %(e)s.") %
                     dict(driver=unicode(store),
                          metadata=unicode(metadata),
                          e=unicode(e)))
            LOG.error(e_msg)
            raise exceptions.BackendException(e_msg)
    return (location, size, checksum, metadata)
Ejemplo n.º 11
0
def create_bucket_if_missing(conf, bucket, s3_conn):
    """
    Creates a missing bucket in S3 if the
    ``s3_store_create_bucket_on_put`` option is set.

    :param conf: Configuration
    :param bucket: Name of bucket to create
    :param s3_conn: Connection to S3
    """
    from boto.exception import S3ResponseError
    try:
        s3_conn.get_bucket(bucket)
    except S3ResponseError as e:
        if e.status == httplib.NOT_FOUND:
            if conf.glance_store.s3_store_create_bucket_on_put:
                host = conf.glance_store.s3_store_host
                location = get_s3_location(host)
                try:
                    s3_conn.create_bucket(bucket, location=location)
                except S3ResponseError as e:
                    msg = (_("Failed to add bucket to S3.\n"
                             "Got error from S3: %s.") %
                           utils.exception_to_str(e))
                    raise glance_store.BackendException(msg)
            else:
                msg = (_("The bucket %(bucket)s does not exist in "
                         "S3. Please set the "
                         "s3_store_create_bucket_on_put option "
                         "to add bucket to S3 automatically.")
                       % {'bucket': bucket})
                raise glance_store.BackendException(msg)
Ejemplo n.º 12
0
    def _create_image_directories(self, directory_paths):
        """
        Create directories to write image files if
        it does not exist.

        :directory_paths is a list of directories belonging to glance store.
        :raises: BadStoreConfiguration exception if creating a directory fails.
        """
        for datadir in directory_paths:
            if os.path.exists(datadir):
                self._check_write_permission(datadir)
                self._set_exec_permission(datadir)
            else:
                msg = _("Directory to write image files does not exist "
                        "(%s). Creating.") % datadir
                LOG.info(msg)
                try:
                    os.makedirs(datadir)
                    self._check_write_permission(datadir)
                    self._set_exec_permission(datadir)
                except (IOError, OSError):
                    if os.path.exists(datadir):
                        # NOTE(markwash): If the path now exists, some other
                        # process must have beat us in the race condition.
                        # But it doesn't hurt, so we can safely ignore
                        # the error.
                        self._check_write_permission(datadir)
                        self._set_exec_permission(datadir)
                        continue
                    reason = _("Unable to create datadir: %s") % datadir
                    LOG.error(reason)
                    raise exceptions.BadStoreConfiguration(
                        store_name="filesystem", reason=reason)
Ejemplo n.º 13
0
    def _get_datadir_path_and_priority(self, datadir):
        """
        Gets directory paths and its priority from
        filesystem_store_datadirs option in glance-api.conf.

        :param datadir: is directory path with its priority.
        :returns: datadir_path as directory path
                 priority as priority associated with datadir_path
        :raises: BadStoreConfiguration exception if priority is invalid or
               empty directory path is specified.
        """
        priority = 0
        parts = [part.strip() for part in datadir.rsplit(":", 1)]
        datadir_path = parts[0]
        if len(parts) == 2 and parts[1]:
            priority = parts[1]
            if not priority.isdigit():
                msg = (_("Invalid priority value %(priority)s in "
                         "filesystem configuration") % {'priority': priority})
                LOG.exception(msg)
                raise exceptions.BadStoreConfiguration(
                    store_name="filesystem", reason=msg)

        if not datadir_path:
            msg = _("Invalid directory specified in filesystem configuration")
            LOG.exception(msg)
            raise exceptions.BadStoreConfiguration(
                store_name="filesystem", reason=msg)

        return datadir_path, priority
Ejemplo n.º 14
0
    def configure_add(self):
        """
        Configure the Store to use the stored configuration options
        Any store that needs special configuration should implement
        this method. If the store was not able to successfully configure
        itself, it should raise `exceptions.BadStoreConfiguration`
        """

        try:
            chunk_size = self.conf.glance_store.sheepdog_store_chunk_size
            self.chunk_size = chunk_size * units.Mi
            self.READ_CHUNKSIZE = self.chunk_size
            self.WRITE_CHUNKSIZE = self.READ_CHUNKSIZE

            self.addr = self.conf.glance_store.sheepdog_store_address
            self.port = self.conf.glance_store.sheepdog_store_port
        except cfg.ConfigFileValueError as e:
            reason = _("Error in store configuration: %s") % e
            LOG.error(reason)
            raise exceptions.BadStoreConfiguration(store_name='sheepdog',
                                                   reason=reason)

        try:
            processutils.execute("collie", shell=True)
        except processutils.ProcessExecutionError as exc:
            reason = _("Error in store configuration: %s") % exc
            LOG.error(reason)
            raise exceptions.BadStoreConfiguration(store_name='sheepdog',
                                                   reason=reason)
Ejemplo n.º 15
0
 def _parse_datastore_info_and_weight(self, datastore):
     weight = 0
     parts = map(lambda x: x.strip(), datastore.rsplit(":", 2))
     if len(parts) < 2:
         msg = _('vmware_datastores format must be '
                 'datacenter_path:datastore_name:weight or '
                 'datacenter_path:datastore_name')
         LOG.error(msg)
         raise exceptions.BadStoreConfiguration(
             store_name='vmware_datastore', reason=msg)
     if len(parts) == 3 and parts[2]:
         weight = parts[2]
         if not weight.isdigit():
             msg = (_('Invalid weight value %(weight)s in '
                      'vmware_datastores configuration') %
                    {'weight': weight})
             LOG.exception(msg)
             raise exceptions.BadStoreConfiguration(
                 store_name="vmware_datastore", reason=msg)
     datacenter_path, datastore_name = parts[0], parts[1]
     if not datacenter_path or not datastore_name:
         msg = _('Invalid datacenter_path or datastore_name specified '
                 'in vmware_datastores configuration')
         LOG.exception(msg)
         raise exceptions.BadStoreConfiguration(
             store_name="vmware_datastore", reason=msg)
     return datacenter_path, datastore_name, weight
 def _sanity_check(self):
     if self.conf.glance_store.vmware_api_retry_count <= 0:
         msg = _("vmware_api_retry_count should be greater than zero")
         LOG.error(msg)
         raise exceptions.BadStoreConfiguration(store_name="vmware_datastore", reason=msg)
     if self.conf.glance_store.vmware_task_poll_interval <= 0:
         msg = _("vmware_task_poll_interval should be greater than zero")
         LOG.error(msg)
         raise exceptions.BadStoreConfiguration(store_name="vmware_datastore", reason=msg)
Ejemplo n.º 17
0
    def _query(self, location, verb, depth=0):
        if depth > MAX_REDIRECTS:
            reason = (_("The HTTP URL exceeded %s maximum "
                        "redirects.") % MAX_REDIRECTS)
            LOG.debug(reason)
            raise exceptions.MaxRedirectsExceeded(message=reason)
        loc = location.store_location
        conn_class = self._get_conn_class(loc)
        conn = conn_class(loc.netloc)
        hearders = {}
        if loc.token:
            # hearders.setdefault('x-auth-token', loc.token)
            # verb = 'GET'
            # conn.request(verb, loc.path, "", hearders)
            # resp = conn.getresponse()
            # try:
            #     size = jsonutils.loads(resp.read())['size']
            # except Exception:
            #     size = 0
            #     raise exception.BadStoreUri(loc.path, reason)
            return (conn, None, 1)

        conn.request(verb, loc.path, "", {})
        resp = conn.getresponse()

        # Check for bad status codes
        if resp.status >= 400:
            if resp.status == httplib.NOT_FOUND:
                reason = _("HTTP datastore could not find image at URI.")
                LOG.debug(reason)
                raise exceptions.NotFound(message=reason)

            reason = (_("HTTP URL %(url)s returned a "
                        "%(status)s status code.") %
                      dict(url=loc.path, status=resp.status))
            LOG.debug(reason)
            raise exceptions.BadStoreUri(message=reason)

        location_header = resp.getheader("location")
        if location_header:
            if resp.status not in (301, 302):
                reason = (_("The HTTP URL %(url)s attempted to redirect "
                            "with an invalid %(status)s status code.") %
                          dict(url=loc.path, status=resp.status))
                LOG.info(reason)
                raise exceptions.BadStoreUri(message=reason)
            location_class = glance_store.location.Location
            new_loc = location_class(location.store_name,
                                     location.store_location.__class__,
                                     uri=location_header,
                                     image_id=location.image_id,
                                     store_specs=location.store_specs)
            return self._query(new_loc, verb, depth + 1)
        content_length = int(resp.getheader('content-length', 0))
        return (conn, resp, content_length)
Ejemplo n.º 18
0
    def configure_add(self):
        """
        Configure the Store to use the stored configuration options
        Any store that needs special configuration should implement
        this method. If the store was not able to successfully configure
        itself, it should raise `exceptions.BadStoreConfiguration`
        """
        self.s3_host = self._option_get('s3_store_host')
        access_key = self._option_get('s3_store_access_key')
        secret_key = self._option_get('s3_store_secret_key')
        if six.PY2:
            # NOTE(jaypipes): Need to encode to UTF-8 here because of a
            # bug in the HMAC library that boto uses.
            # See: http://bugs.python.org/issue5285
            # See: http://trac.edgewall.org/ticket/8083
            access_key = access_key.encode('utf-8')
            secret_key = secret_key.encode('utf-8')
        self.access_key = access_key
        self.secret_key = secret_key
        self.bucket = self._option_get('s3_store_bucket')

        self.scheme = 's3'
        if self.s3_host.startswith('https://'):
            self.scheme = 's3+https'
            self.full_s3_host = self.s3_host
        elif self.s3_host.startswith('http://'):
            self.full_s3_host = self.s3_host
        else:  # Defaults http
            self.full_s3_host = 'http://' + self.s3_host

        buffer_dir = self.conf.glance_store.s3_store_object_buffer_dir
        self.s3_store_object_buffer_dir = buffer_dir

        _s3_obj_size = self._option_get('s3_store_large_object_size')
        self.s3_store_large_object_size = _s3_obj_size * units.Mi
        _s3_ck_size = self._option_get('s3_store_large_object_chunk_size')
        _s3_ck_min = DEFAULT_LARGE_OBJECT_MIN_CHUNK_SIZE
        if _s3_ck_size < _s3_ck_min:
            reason = (_("s3_store_large_object_chunk_size must be at "
                        "least %(_s3_ck_min)d MB. "
                        "You configured it as %(_s3_ck_size)d MB") %
                      {'_s3_ck_min': _s3_ck_min,
                       '_s3_ck_size': _s3_ck_size})
            LOG.error(reason)
            raise exceptions.BadStoreConfiguration(store_name="s3",
                                                   reason=reason)
        self.s3_store_large_object_chunk_size = _s3_ck_size * units.Mi
        self.s3_store_thread_pools = self._option_get('s3_store_thread_pools')
        if self.s3_store_thread_pools <= 0:
            reason = (_("s3_store_thread_pools must be a positive "
                        "integer. %s") % self.s3_store_thread_pools)
            LOG.error(reason)
            raise exceptions.BadStoreConfiguration(store_name="s3",
                                                   reason=reason)
Ejemplo n.º 19
0
def verify_store():
    store_id = CONF.glance_store.default_backend
    if not store_id:
        msg = _("'default_backend' config option is not set.")
        raise RuntimeError(msg)

    try:
        get_store_from_store_identifier(store_id)
    except exceptions.UnknownScheme:
        msg = _("Store for identifier %s not found") % store_id
        raise RuntimeError(msg)
Ejemplo n.º 20
0
 def _check_context(self, context, require_tenant=False):
     user_overriden = is_user_overriden(self.conf)
     if user_overriden and not require_tenant:
         return
     if context is None:
         reason = _("Cinder storage requires a context.")
         raise exceptions.BadStoreConfiguration(store_name="cinder",
                                                reason=reason)
     if not user_overriden and context.service_catalog is None:
         reason = _("Cinder storage requires a service catalog.")
         raise exceptions.BadStoreConfiguration(store_name="cinder",
                                                reason=reason)
Ejemplo n.º 21
0
    def _delete_image(self, target_pool, image_name,
                      snapshot_name=None, context=None):
        """
        Delete RBD image and snapshot.

        :param image_name: Image's name
        :param snapshot_name: Image snapshot's name

        :raises: NotFound if image does not exist;
                InUseByStore if image is in use or snapshot unprotect failed
        """
        with self.get_connection(conffile=self.conf_file,
                                 rados_id=self.user) as conn:
            with conn.open_ioctx(target_pool) as ioctx:
                try:
                    # First remove snapshot.
                    if snapshot_name is not None:
                        with rbd.Image(ioctx, image_name) as image:
                            try:
                                self._unprotect_snapshot(image, snapshot_name)
                                image.remove_snap(snapshot_name)
                            except rbd.ImageNotFound as exc:
                                msg = (_("Snap Operating Exception "
                                         "%(snap_exc)s "
                                         "Snapshot does not exist.") %
                                       {'snap_exc': exc})
                                LOG.debug(msg)
                            except rbd.ImageBusy as exc:
                                log_msg = (_LE("Snap Operating Exception "
                                               "%(snap_exc)s "
                                               "Snapshot is in use.") %
                                           {'snap_exc': exc})
                                LOG.error(log_msg)
                                raise exceptions.InUseByStore()

                    # Then delete image.
                    rbd.RBD().remove(ioctx, image_name)
                except rbd.ImageHasSnapshots:
                    log_msg = (_LE("Remove image %(img_name)s failed. "
                                   "It has snapshot(s) left.") %
                               {'img_name': image_name})
                    LOG.error(log_msg)
                    raise exceptions.HasSnapshot()
                except rbd.ImageBusy:
                    log_msg = (_LE("Remove image %(img_name)s failed. "
                                   "It is in use.") %
                               {'img_name': image_name})
                    LOG.error(log_msg)
                    raise exceptions.InUseByStore()
                except rbd.ImageNotFound:
                    msg = _("RBD image %s does not exist") % image_name
                    raise exceptions.NotFound(message=msg)
Ejemplo n.º 22
0
    def parse_uri(self, uri):
        if not uri.startswith('cinder://'):
            reason = _("URI must start with 'cinder://'")
            LOG.info(reason)
            raise exceptions.BadStoreUri(message=reason)

        self.scheme = 'cinder'
        self.volume_id = uri[9:]

        if not utils.is_uuid_like(self.volume_id):
            reason = _("URI contains invalid volume ID")
            LOG.info(reason)
            raise exceptions.BadStoreUri(message=reason)
Ejemplo n.º 23
0
    def _query(self, location, method, depth=0):
        if depth > MAX_REDIRECTS:
            msg = ("The HTTP URL exceeded %(max_redirects)s maximum "
                   "redirects.", {'max_redirects': MAX_REDIRECTS})
            LOG.debug(msg)
            raise exceptions.MaxRedirectsExceeded(redirects=MAX_REDIRECTS)
        loc = location.store_location
        # NOTE(arnaud): use a decorator when the config is not tied to self
        for i in range(self.api_retry_count + 1):
            cookie = self._build_vim_cookie_header(
                self.session.vim.client.options.transport.cookiejar)
            headers = {'Cookie': cookie}
            try:
                conn = self._get_http_conn(method, loc, headers)
                resp = conn.getresponse()
            except Exception:
                with excutils.save_and_reraise_exception():
                    LOG.exception(_LE('Failed to access image %(image)s '
                                      'content.') % {'image':
                                                     location.image_id})
            if resp.status >= 400:
                if resp.status == httplib.UNAUTHORIZED:
                    self.reset_session(force=True)
                    continue
                if resp.status == httplib.NOT_FOUND:
                    reason = _('VMware datastore could not find image at URI.')
                    LOG.info(reason)
                    raise exceptions.NotFound(message=reason)
                msg = ('HTTP request returned a %(status)s status code.'
                       % {'status': resp.status})
                LOG.debug(msg)
                raise exceptions.BadStoreUri(msg)
            break
        location_header = resp.getheader('location')
        if location_header:
            if resp.status not in (301, 302):
                reason = (_("The HTTP URL %(path)s attempted to redirect "
                            "with an invalid %(status)s status code.")
                          % {'path': loc.path, 'status': resp.status})
                LOG.info(reason)
                raise exceptions.BadStoreUri(message=reason)
            location_class = glance_store.location.Location
            new_loc = location_class(location.store_name,
                                     location.store_location.__class__,
                                     uri=location_header,
                                     image_id=location.image_id,
                                     store_specs=location.store_specs)
            return self._query(new_loc, method, depth + 1)
        content_length = int(resp.getheader('content-length', 0))

        return (conn, resp, content_length)
Ejemplo n.º 24
0
    def add(self, image_id, image_file, image_size, context=None):
        """Stores an image file with supplied identifier to the backend
        storage system and returns a tuple containing information
        about the stored image.

        :param image_id: The opaque image identifier
        :param image_file: The image data to write, as a file-like object
        :param image_size: The size of the image data to write, in bytes
        :retval tuple of URL in backing store, bytes written, checksum
                and a dictionary with storage system specific information
        :raises `glance.common.exceptions.Duplicate` if the image already
                existed
                `glance.common.exceptions.UnexpectedStatus` if the upload
                request returned an unexpected status. The expected responses
                are 201 Created and 200 OK.
        """
        checksum = hashlib.md5()
        image_file = _Reader(image_file, checksum)
        loc = StoreLocation({'scheme': self.scheme,
                             'server_host': self.server_host,
                             'image_dir': self.store_image_dir,
                             'datacenter_path': self.datacenter_path,
                             'datastore_name': self.datastore_name,
                             'image_id': image_id})
        cookie = self._build_vim_cookie_header(
            self._session.vim.client.options.transport.cookiejar)
        headers = {'Connection': 'Keep-Alive',
                   'Cookie': cookie,
                   'Transfer-Encoding': 'chunked'}
        try:
            conn = self._get_http_conn('PUT', loc, headers,
                                       content=image_file)
            res = conn.getresponse()
        except Exception:
            with excutils.save_and_reraise_exception():
                LOG.exception(_('Failed to upload content of image '
                                '%(image)s') % {'image': image_id})

        if res.status == httplib.CONFLICT:
            raise exceptions.Duplicate(_("Image file %(image_id)s already "
                                         "exists!") % {'image_id': image_id})

        if res.status not in (httplib.CREATED, httplib.OK):
            msg = (_('Failed to upload content of image %(image)s') %
                   {'image': image_id})
            LOG.error(msg)
            raise exceptions.UnexpectedStatus(status=res.status,
                                              body=res.read())

        return (loc.get_uri(), image_file.size, checksum.hexdigest(), {})
Ejemplo n.º 25
0
def safe_delete_from_backend(uri, image_id, context=None):
    """Given a uri, delete an image from the store."""
    try:
        return delete_from_backend(uri, context=context)
    except exceptions.NotFound:
        msg = _('Failed to delete image %s in store from URI')
        LOG.warn(msg % image_id)
    except exceptions.StoreDeleteNotSupported as e:
        LOG.warn(str(e))
    except exceptions.UnsupportedBackend:
        exc_type = sys.exc_info()[0].__name__
        msg = (_('Failed to delete image %(image_id)s '
                 'from store (%(exc_type)s)') %
               dict(image_id=image_id, exc_type=exc_type))
        LOG.error(msg)
    def connect_and_confirm(self):
        """ 
        Confirm connection to irods with the given credentials 
        
        """
        

        try:
            msg = (_("connecting to irods://%(host)s:%(port)s%(path)s " +
                     "in zone %(zone)s") %
                   ({'host': self.host, 'port': self.port,
                     'path': self.datastore, 'zone': self.zone}))

            LOG.debug(msg)
            sess = iRODSSession(user=str(self.user), password=str(self.password), host=str(
                self.host), port=int(self.port), zone=str(self.zone))

            coll = sess.collections.get(self.test_path)

        except Exception as e:
            reason = (_("Could not connect with host, port, zone," +
                        " path, or user/password. %s" % (e)))
            LOG.error(reason)
            raise exceptions.BadStoreConfiguration(store_name="irods",
                                                  reason=reason)
        else:
            self.irods_conn_object = sess
            self.irods_conn_object.cleanup()
        finally:
            sess.cleanup()
            

        # check if file exists

        LOG.debug(_("attempting to check the collection %s" % self.datastore))
        try:
            coll = sess.collections.get(self.datastore)
        except Exception:
            reason = _("collection '%s' is not valid or must be " +
                       "created beforehand") % self.datastore
            LOG.error(reason)
            raise exceptions.BadStoreConfiguration(store_name="irods",
                                                  reason=reason)
        finally:
            sess.cleanup()

        LOG.debug(_("success"))
        return True
Ejemplo n.º 27
0
    def delete(self, location, context=None):
        """
        Takes a `glance_store.location.Location` object that indicates
        where to find the image file to delete

        :location `glance_store.location.Location` object, supplied
                  from glance_store.location.get_location_from_uri()

        :raises NotFound if image does not exist
        """
        loc = location.store_location
        s3host, s3port = netutils.parse_host_port(loc.s3serviceurl, 80)
        from boto.s3.connection import S3Connection

        uformat = self.conf.glance_store.s3_store_bucket_url_format
        calling_format = get_calling_format(s3_store_bucket_url_format=uformat)

        s3_conn = S3Connection(loc.accesskey, loc.secretkey,
                               host=s3host, port=s3port,
                               is_secure=(loc.scheme == 's3+https'),
                               calling_format=calling_format)
        bucket_obj = get_bucket(s3_conn, loc.bucket)

        # Close the key when we're through.
        key = get_key(bucket_obj, loc.key)

        msg = _("Deleting image object from S3 using (s3_host=%(s3_host)s, "
                "access_key=%(accesskey)s, bucket=%(bucket)s, "
                "key=%(obj_name)s)") % ({'s3_host': loc.s3serviceurl,
                                         'accesskey': loc.accesskey,
                                         'bucket': loc.bucket,
                                         'obj_name': loc.key})
        LOG.debug(msg)

        return key.delete()
Ejemplo n.º 28
0
    def get_size(self, location, context=None):
        """
        Takes a `glance_store.location.Location` object that indicates
        where to find the image file, and returns the size

        :param location `glance_store.location.Location` object, supplied
                        from glance_store.location.get_location_from_uri()
        :raises `glance_store.exceptions.NotFound` if image does not exist
        """
        loc = location.store_location
        # if there is a pool specific in the location, use it; otherwise
        # we fall back to the default pool specified in the config
        target_pool = loc.pool or self.pool
        with rados.Rados(conffile=self.conf_file,
                         rados_id=self.user) as conn:
            with conn.open_ioctx(target_pool) as ioctx:
                try:
                    with rbd.Image(ioctx, loc.image,
                                   snapshot=loc.snapshot) as image:
                        img_info = image.stat()
                        return img_info['size']
                except rbd.ImageNotFound:
                    msg = _('RBD image %s does not exist') % loc.get_uri()
                    LOG.debug(msg)
                    raise exceptions.NotFound(msg)
Ejemplo n.º 29
0
    def _check_context(self, context):
        """
        Configure the Store to use the stored configuration options
        Any store that needs special configuration should implement
        this method. If the store was not able to successfully configure
        itself, it should raise `exceptions.BadStoreConfiguration`
        """

        if context is None:
            reason = _("Cinder storage requires a context.")
            raise exceptions.BadStoreConfiguration(store_name="cinder",
                                                   reason=reason)
        if context.service_catalog is None:
            reason = _("Cinder storage requires a service catalog.")
            raise exceptions.BadStoreConfiguration(store_name="cinder",
                                                   reason=reason)
Ejemplo n.º 30
0
def verify_default_store():
    scheme = CONF.glance_store.default_store
    try:
        get_store_from_scheme(scheme)
    except exceptions.UnknownScheme:
        msg = _("Store for scheme %s not found") % scheme
        raise RuntimeError(msg)
Ejemplo n.º 31
0
def get_cinderclient(conf, context=None):
    glance_store = conf.glance_store
    user_overriden = is_user_overriden(conf)
    if user_overriden:
        username = glance_store.cinder_store_user_name
        password = glance_store.cinder_store_password
        project = glance_store.cinder_store_project_name
        url = glance_store.cinder_store_auth_address
    else:
        username = context.user
        password = context.auth_token
        project = context.tenant

        if glance_store.cinder_endpoint_template:
            url = glance_store.cinder_endpoint_template % context.to_dict()
        else:
            info = glance_store.cinder_catalog_info
            service_type, service_name, interface = info.split(':')
            try:
                catalog = keystone_sc.ServiceCatalogV2(context.service_catalog)
                url = catalog.url_for(
                    region_name=glance_store.cinder_os_region_name,
                    service_type=service_type,
                    service_name=service_name,
                    interface=interface)
            except keystone_exc.EndpointNotFound:
                reason = _("Failed to find Cinder from a service catalog.")
                raise exceptions.BadStoreConfiguration(store_name="cinder",
                                                       reason=reason)

    c = cinderclient.Client(username,
                            password,
                            project,
                            auth_url=url,
                            insecure=glance_store.cinder_api_insecure,
                            retries=glance_store.cinder_http_retries,
                            cacert=glance_store.cinder_ca_certificates_file)

    LOG.debug('Cinderclient connection created for user %(user)s using URL: '
              '%(url)s.', {'user': username, 'url': url})

    # noauth extracts user_id:project_id from auth_token
    if not user_overriden:
        c.client.auth_token = context.auth_token or '%s:%s' % (username,
                                                               project)
    c.client.management_url = url
    return c
Ejemplo n.º 32
0
    def parse_uri(self, uri):
        """
        Parse URLs. This method fixes an issue where credentials specified
        in the URL are interpreted differently in Python 2.6.1+ than prior
        versions of Python.
        """
        pieces = urllib.parse.urlparse(uri)
        assert pieces.scheme in ('https', 'http')
        self.scheme = pieces.scheme
        netloc = pieces.netloc
        path = pieces.path
        try:
            if '@' in netloc:
                creds, netloc = netloc.split('@')
            else:
                creds = None
        except ValueError:
            # Python 2.6.1 compat
            # see lp659445 and Python issue7904
            if '@' in path:
                creds, path = path.split('@')
            else:
                creds = None
        if creds:
            try:
                self.user, self.password = creds.split(':')
            except ValueError:
                reason = _("Credentials are not well-formatted.")
                LOG.info(reason)
                raise exceptions.BadStoreUri(message=reason)
        else:
            self.user = None
        if netloc == '':
            LOG.info(_LI("No address specified in HTTP URL"))
            raise exceptions.BadStoreUri(uri=uri)
        else:
            # IPv6 address has the following format [1223:0:0:..]:<some_port>
            # we need to be sure that we are validating port in both IPv4,IPv6
            delimiter = "]:" if netloc.count(":") > 1 else ":"
            host, dlm, port = netloc.partition(delimiter)
            # if port is present in location then validate port format
            if port and not port.isdigit():
                raise exceptions.BadStoreUri(uri=uri)

        self.netloc = netloc
        self.path = path
Ejemplo n.º 33
0
    def get(self, location, offset=0, chunk_size=None, context=None):
        """
        Takes a `glance_store.location.Location` object that indicates
        where to find the image file, and returns a tuple of generator
        (for reading the image file) and image_size

        :param location: `glance_store.location.Location` object, supplied
                        from glance_store.location.get_location_from_uri()
        :raises: `glance_store.exceptions.NotFound` if image does not exist
        """
        filepath, filesize = self._resolve_location(location)
        msg = _("Found image at %s. Returning in ChunkedFile.") % filepath
        LOG.debug(msg)
        return (ChunkedFile(filepath,
                            offset=offset,
                            chunk_size=self.READ_CHUNKSIZE,
                            partial_length=chunk_size), chunk_size or filesize)
Ejemplo n.º 34
0
def register_store_opts(conf):
    for store_entry in set(conf.glance_store.stores):
        LOG.debug("Registering options for %s" % store_entry)
        store_cls = _load_store(conf, store_entry, False)

        if store_cls is None:
            msg = _('Store %s not found') % store_entry
            raise exceptions.GlanceStoreException(message=msg)

        if getattr(store_cls, 'OPTIONS', None) is not None:
            # NOTE(flaper87): To be removed in k-2. This should
            # give deployers enough time to migrate their systems
            # and move configs under the new section.
            for opt in store_cls.OPTIONS:
                opt.deprecated_opts = [cfg.DeprecatedOpt(opt.name,
                                                         group='DEFAULT')]
                conf.register_opt(opt, group=_STORE_CFG_GROUP)
Ejemplo n.º 35
0
def get_store_from_store_identifier(store_identifier):
    """Determine backing store from identifier.

    Given a store identifier, return the appropriate store object
    for handling that scheme.
    """
    scheme_map = {}
    enabled_backends = CONF.enabled_backends
    try:
        scheme = enabled_backends[store_identifier]
    except KeyError:
        msg = _("Store for identifier %s not found") % store_identifier
        raise exceptions.UnknownScheme(msg)

    if scheme not in location.SCHEME_TO_CLS_BACKEND_MAP:
        raise exceptions.UnknownScheme(scheme=scheme)

    scheme_info = location.SCHEME_TO_CLS_BACKEND_MAP[scheme][store_identifier]
    store = scheme_info['store']

    if not store.is_capable(capabilities.BitMasks.DRIVER_REUSABLE):
        # Driver instance isn't stateless so it can't
        # be reused safely and need recreation.
        store_entry = scheme_info['store_entry']
        store = _load_multi_store(store.conf,
                                  store_entry,
                                  invoke_load=True,
                                  backend=store_identifier)
        store.configure()
        try:
            loc_cls = store.get_store_location_class()
            for new_scheme in store.get_schemes():
                if new_scheme not in scheme_map:
                    scheme_map[new_scheme] = {}

                scheme_map[new_scheme][store_identifier] = {
                    'store': store,
                    'location_class': loc_cls,
                    'store_entry': store_entry
                }
                location.register_scheme_backend_map(scheme_map)
        except NotImplementedError:
            scheme_info['store'] = store

    return store
Ejemplo n.º 36
0
    def get(self, location, offset=0, chunk_size=None, context=None):
        """
        Takes a `glance_store.location.Location` object that indicates
        where to find the image file, and returns a generator for reading
        the image file

        :param location: `glance_store.location.Location` object, supplied
                        from glance_store.location.get_location_from_uri()
        :raises: `glance_store.exceptions.NotFound` if image does not exist
        """

        loc = location.store_location
        image = SheepdogImage(loc.addr, loc.port, loc.image,
                              self.READ_CHUNKSIZE)
        if not image.exist():
            raise exceptions.NotFound(
                _("Sheepdog image %s does not exist") % image.name)
        return (ImageIterator(image), image.get_size())
Ejemplo n.º 37
0
 def parse_uri(self, uri):
     """Parse URLs based on GCE scheme """
     LOG.debug('Parse uri %s' % (uri, ))
     if not uri.startswith('%s://' % STORE_SCHEME):
         reason = (_("URI %(uri)s must start with %(scheme)s://") % {
             'uri': uri,
             'scheme': STORE_SCHEME
         })
         LOG.error(reason)
         raise exceptions.BadStoreUri(message=reason)
     pieces = urllib.parse.urlparse(uri)
     self.scheme = pieces.scheme
     gce_project = pieces.netloc
     gce_id, glance_id = pieces.path.strip('/').split('/')
     parse_params = (gce_project, gce_id, glance_id)
     if not all([parse_params]):
         raise exceptions.BadStoreUri(uri=uri)
     self.gce_project, self.gce_id, self.glance_id = parse_params
Ejemplo n.º 38
0
    def get_size(self, location, context=None):
        """
        Takes a `glance_store.location.Location` object that indicates
        where to find the image file and returns the image size

        :param location: `glance_store.location.Location` object, supplied
                        from glance_store.location.get_location_from_uri()
        :raises: `glance_store.exceptions.NotFound` if image does not exist
        :rtype: int
        """

        loc = location.store_location
        image = SheepdogImage(loc.addr, loc.port, loc.image,
                              self.READ_CHUNKSIZE)
        if not image.exist():
            raise exceptions.NotFound(
                _("Sheepdog image %s does not exist") % image.name)
        return image.get_size()
Ejemplo n.º 39
0
 def __iter__(self):
     try:
         with self.store.get_connection(conffile=self.conf_file,
                                        rados_id=self.user) as conn:
             with conn.open_ioctx(self.pool) as ioctx:
                 with rbd.Image(ioctx, self.name,
                                snapshot=self.snapshot) as image:
                     size = image.size()
                     bytes_left = size
                     while bytes_left > 0:
                         length = min(self.chunk_size, bytes_left)
                         data = image.read(size - bytes_left, length)
                         bytes_left -= len(data)
                         yield data
                     raise StopIteration()
     except rbd.ImageNotFound:
         raise exceptions.NotFound(
             _('RBD image %s does not exist') % self.name)
Ejemplo n.º 40
0
 def __iter__(self):
     try:
         with rados.Rados(conffile=self.conf_file,
                          rados_id=self.user) as conn:
             with conn.open_ioctx(self.pool) as ioctx:
                 with rbd.Image(ioctx, self.name) as image:
                     img_info = image.stat()
                     size = img_info['size']
                     bytes_left = size
                     while bytes_left > 0:
                         length = min(self.chunk_size, bytes_left)
                         data = image.read(size - bytes_left, length)
                         bytes_left -= len(data)
                         yield data
                     raise StopIteration()
     except rbd.ImageNotFound:
         raise exceptions.NotFound(
             _('RBD image %s does not exist') % self.name)
Ejemplo n.º 41
0
    def delete(self, location, context=None):
        """
        Takes a `glance.store.location.Location` object that indicates
        where to find the image file to delete
        :location `glance.store.location.Location` object, supplied
                  from glance.store.location.get_location_from_uri()
        :raises NotFound if image does not exist
        :raises Forbidden if cannot delete because of permissions
        """
        full_data_path = self.path + "/" + location.store_location.data_name

        LOG.debug(
            _("connecting to %(host)s for %(data)s" % ({
                'host': self.host,
                'data': full_data_path
            })))

        self.irods_manager.delete_image_file(full_data_path)
Ejemplo n.º 42
0
def get_key(bucket, obj):
    """
    Get a key from a bucket

    :param bucket: The ``boto.s3.Bucket``
    :param obj: Object to get the key for
    :raises ``glance_store.exceptions.NotFound`` if key is not found.
    """

    key = bucket.get_key(obj)
    if not key or not key.exists():
        msg = (_("Could not find key %(obj)s in bucket %(bucket)s") % {
            'obj': obj,
            'bucket': bucket
        })
        LOG.debug(msg)
        raise exceptions.NotFound(message=msg)
    return key
Ejemplo n.º 43
0
    def delete(self, location, context=None):
        """
        Takes a `glance_store.location.Location` object that indicates
        where to find the image file to delete

        :param location: `glance_store.location.Location` object, supplied
                  from glance_store.location.get_location_from_uri()

        :raises: NotFound if image does not exist
        """

        loc = location.store_location
        image = SheepdogImage(loc.addr, loc.port, loc.image,
                              self.WRITE_CHUNKSIZE)
        if not image.exist():
            raise exceptions.NotFound(
                _("Sheepdog image %s does not exist") % loc.image)
        image.delete()
Ejemplo n.º 44
0
    def add(self,
            image_id,
            image_file,
            image_size,
            context=None,
            verifier=None):
        """
        Stores an image file with supplied identifier to the backend
        storage system and returns an `glance.store.ImageAddResult` object
        containing information about the stored image.
        :param image_id: The opaque image identifier
        :param image_file: The image data to write, as a file-like object
        :param image_size: The size of the image data to write, in bytes
        :retval `glance.store.ImageAddResult` object
        :raises `glance.common.exception.Duplicate` if the image already
                existed
        :note By default, the backend writes the image data to a file
              `/<DATADIR>/<ID>`, where <DATADIR> is the value of
              the filesystem_store_datadir configuration option and <ID>
              is the supplied image ID.
        """
        full_data_path = self.path + "/" + image_id

        LOG.debug(
            _("connecting to %(host)s for %(data)s" % ({
                'host': self.host,
                'data': full_data_path
            })))

        bytes_written, checksum_hex = self.irods_manager.add_image_file(
            full_data_path, image_file)

        loc = StoreLocation(
            {
                'scheme': 'irods',
                'host': self.host,
                'port': self.port,
                'zone': self.zone,
                'path': self.path,
                'user': self.user,
                'password': self.password,
                'data_name': image_id
            }, None)
        return (loc.get_uri(), bytes_written, checksum_hex, {})
Ejemplo n.º 45
0
    def _load_config(self):
        if self.backend_group:
            scf = getattr(self.conf,
                          self.backend_group).swift_store_config_file
        else:
            scf = self.conf.glance_store.swift_store_config_file
        try:
            conf_file = self.conf.find_file(scf)
            CONFIG.read(conf_file)
        except Exception as e:
            msg = (_("swift config file "
                     "%(conf)s:%(exc)s not found"), {
                         'conf': scf,
                         'exc': e
                     })
            LOG.error(msg)
            raise exceptions.BadStoreConfiguration(store_name='swift',
                                                   reason=msg)
        account_params = {}
        account_references = CONFIG.sections()

        for ref in account_references:
            reference = {}
            try:
                for param in ('auth_address', 'user', 'key',
                              'project_domain_id', 'project_domain_name',
                              'user_domain_id', 'user_domain_name'):
                    reference[param] = CONFIG.get(ref, param)

                try:
                    reference['auth_version'] = CONFIG.get(ref, 'auth_version')
                except configparser.NoOptionError:
                    if self.backend_group:
                        av = getattr(
                            self.conf,
                            self.backend_group).swift_store_auth_version
                    else:
                        av = self.conf.glance_store.swift_store_auth_version
                    reference['auth_version'] = av

                account_params[ref] = reference
            except (ValueError, SyntaxError, configparser.NoOptionError):
                LOG.exception(_LE("Invalid format of swift store config cfg"))
        return account_params
Ejemplo n.º 46
0
    def get_connection(self, conffile, rados_id):
        client = rados.Rados(conffile=conffile, rados_id=rados_id)

        try:
            client.connect(timeout=self.connect_timeout)
        except (rados.Error, rados.ObjectNotFound) as e:
            if self.backend_group and len(self.conf.enabled_backends) > 1:
                reason = _("Error in store configuration: %s") % e
                LOG.debug(reason)
                raise exceptions.BadStoreConfiguration(
                    store_name=self.backend_group, reason=reason)
            else:
                msg = _LE("Error connecting to ceph cluster.")
                LOG.exception(msg)
                raise exceptions.BackendException()
        try:
            yield client
        finally:
            client.shutdown()
Ejemplo n.º 47
0
    def get_size(self, location, context=None):
        """
        Takes a `glance_store.location.Location` object that indicates
        where to find the image file, and returns the size

        :param location `glance_store.location.Location` object, supplied
                        from glance_store.location.get_location_from_uri()
        """
        try:
            size = self._query(location, 'HEAD')[2]
        except socket.error:
            reason = _("The HTTP URL is invalid.")
            LOG.info(reason)
            raise exceptions.BadStoreUri(message=reason)
        except Exception:
            # NOTE(flaper87): Catch more granular exceptions,
            # keeping this branch for backwards compatibility.
            return 0
        return size
Ejemplo n.º 48
0
    def _get_storage_url(self):
        """Get swift endpoint from keystone

        Return endpoint for swift from service catalog. The method works only
        Keystone v3. If you are using different version (1 or 2)
        it returns None.
        :return: swift endpoint
        """
        if self.store.auth_version == '3':
            try:
                return self.client.session.get_endpoint(
                    service_type=self.store.service_type,
                    interface=self.store.endpoint_type,
                    region_name=self.store.region)
            except Exception as e:
                # do the same that swift driver does
                # when catching ClientException
                msg = _("Cannot find swift service endpoint : "
                        "%s") % encodeutils.exception_to_unicode(e)
                raise exceptions.BackendException(msg)
Ejemplo n.º 49
0
    def get_image_file_size(self, full_data_path):
        """
        Returns image size for the file specified or returns 0
        """
        try:

            file_object = self.irods_conn_object.data_objects.get(
                full_data_path)

        except:
            msg = _("image size %s not found") % full_data_path
            Log.error(msg)
            return 0

        LOG.debug("path = %(path)s, size = %(data_size)s" %
                  ({
                      'path': full_data_path,
                      'data_size': file_object.size
                  }))
        return file_object.size
Ejemplo n.º 50
0
    def get_size(self, location, context=None):
        """
        Takes a `glance_store.location.Location` object that indicates
        where to find the image file, and returns the size

        :param location: `glance_store.location.Location` object, supplied
                        from glance_store.location.get_location_from_uri()
        :raises: `glance_store.exceptions.NotFound` if image does not exist
        """
        LOG.debug(
            _("get_size() called with location: %s, context: %s" %
              (location, context)))
        try:
            image = self._image_from_location(location.store_location)
            return image.data_size
        except Exception as e:
            # Logging exceptions here because Glance has a tendancy to
            # suppress them
            LOG.error(e, exc_info=1)
            raise
Ejemplo n.º 51
0
    def configure_add(self):
        """
        Configure the Store to use the stored configuration options
        Any store that needs special configuration should implement
        this method. If the store was not able to successfully configure
        itself, it should raise `exceptions.BadStoreConfiguration`
        """
        if pymongo is None:
            msg = _("Missing dependencies: pymongo")
            raise exceptions.BadStoreConfiguration(store_name="gridfs",
                                                   reason=msg)

        self.mongodb_uri = self._option_get('mongodb_store_uri')

        parsed = uri_parser.parse_uri(self.mongodb_uri)
        self.mongodb_db = self._option_get('mongodb_store_db') or \
            parsed.get("database")

        self.mongodb = pymongo.MongoClient(self.mongodb_uri)
        self.fs = gridfs.GridFS(self.mongodb[self.mongodb_db])
Ejemplo n.º 52
0
def set_acls(location_uri,
             public=False,
             read_tenants=[],
             write_tenants=None,
             context=None):

    if write_tenants is None:
        write_tenants = []

    loc = location.get_location_from_uri(location_uri, conf=CONF)
    scheme = get_store_from_location(location_uri)
    store = get_store_from_scheme(scheme)
    try:
        store.set_acls(loc,
                       public=public,
                       read_tenants=read_tenants,
                       write_tenants=write_tenants,
                       context=context)
    except NotImplementedError:
        LOG.debug(_("Skipping store.set_acls... not implemented."))
Ejemplo n.º 53
0
    def _query(self, location, method):
        session = new_session(self.api_insecure, self.ca_file)
        loc = location.store_location
        redirects_followed = 0
        # TODO(sabari): The redirect logic was added to handle cases when the
        # backend redirects http url's to https. But the store never makes a
        # http request and hence this can be safely removed.
        while redirects_followed < MAX_REDIRECTS:
            conn, resp = self._retry_request(session, method, location)

            # NOTE(sigmavirus24): _retry_request handles 4xx and 5xx errors so
            # if the response is not a redirect, we can return early.
            if not conn.is_redirect:
                break

            redirects_followed += 1

            location_header = conn.headers.get('location')
            if location_header:
                if resp.status not in (301, 302):
                    reason = (_("The HTTP URL %(path)s attempted to redirect "
                                "with an invalid %(status)s status code.") % {
                                    'path': loc.path,
                                    'status': resp.status
                                })
                    LOG.info(reason)
                    raise exceptions.BadStoreUri(message=reason)
                conn.close()
                location = self._new_location(location, location_header)
        else:
            # NOTE(sigmavirus24): We exceeded the maximum number of redirects
            msg = ("The HTTP URL exceeded %(max_redirects)s maximum "
                   "redirects.", {
                       'max_redirects': MAX_REDIRECTS
                   })
            LOG.debug(msg)
            raise exceptions.MaxRedirectsExceeded(redirects=MAX_REDIRECTS)

        content_length = int(resp.getheader('content-length', 0))

        return (conn, resp, content_length)
Ejemplo n.º 54
0
    def configure_add(self):
        """
        Configure the Store to use the stored configuration options
        Any store that needs special configuration should implement
        this method. If the store was not able to successfully configure
        itself, it should raise `exceptions.BadStoreConfiguration`
        """
        try:
            if self.backend_group:
                chunk = getattr(self.conf,
                                self.backend_group).rbd_store_chunk_size
                pool = getattr(self.conf, self.backend_group).rbd_store_pool
                user = getattr(self.conf, self.backend_group).rbd_store_user
                conf_file = getattr(self.conf,
                                    self.backend_group).rbd_store_ceph_conf
                connect_timeout = getattr(
                    self.conf, self.backend_group).rados_connect_timeout
            else:
                chunk = self.conf.glance_store.rbd_store_chunk_size
                pool = self.conf.glance_store.rbd_store_pool
                user = self.conf.glance_store.rbd_store_user
                conf_file = self.conf.glance_store.rbd_store_ceph_conf
                connect_timeout = self.conf.glance_store.rados_connect_timeout

            self.chunk_size = chunk * units.Mi
            self.READ_CHUNKSIZE = self.chunk_size
            self.WRITE_CHUNKSIZE = self.READ_CHUNKSIZE

            # these must not be unicode since they will be passed to a
            # non-unicode-aware C library
            self.pool = str(pool)
            self.user = str(user)
            self.conf_file = str(conf_file)
            self.connect_timeout = connect_timeout
        except cfg.ConfigFileValueError as e:
            reason = _("Error in store configuration: %s") % e
            LOG.error(reason)
            raise exceptions.BadStoreConfiguration(store_name='rbd',
                                                   reason=reason)
        if self.backend_group:
            self._set_url_prefix()
Ejemplo n.º 55
0
    def add(self, image_id, image_file, image_size, context=None):
        """
        Stores an image file with supplied identifier to the backend
        storage system and returns a tuple containing information
        about the stored image.

        :param image_id: The opaque image identifier
        :param image_file: The image data to write, as a file-like object
        :param image_size: The size of the image data to write, in bytes

        :retval tuple of URL in backing store, bytes written, and checksum
        :raises `glance_store.exceptions.Duplicate` if the image already
                existed
        """

        image = SheepdogImage(self.addr, self.port, image_id,
                              self.WRITE_CHUNKSIZE)
        if image.exist():
            raise exceptions.Duplicate(
                _("Sheepdog image %s already exists") % image_id)

        location = StoreLocation({'image': image_id})
        checksum = hashlib.md5()

        image.create(image_size)

        try:
            total = left = image_size
            while left > 0:
                length = min(self.chunk_size, left)
                data = image_file.read(length)
                image.write(data, total - left, length)
                left -= length
                checksum.update(data)
        except Exception:
            # Note(zhiyan): clean up already received data when
            # error occurs such as ImageSizeLimitExceeded exceptions.
            with excutils.save_and_reraise_exception():
                image.delete()

        return (location.get_uri(), image_size, checksum.hexdigest(), {})
Ejemplo n.º 56
0
    def _v2_auth(self, token_url):

        creds = self.creds

        creds = {
            "auth": {
                "tenantName": creds['tenant'],
                "passwordCredentials": {
                    "username": creds['username'],
                    "password": creds['password']
                }
            }
        }

        headers = {}
        headers['Content-Type'] = 'application/json'
        req_body = jsonutils.dumps(creds)

        resp, resp_body = self._do_request(token_url,
                                           'POST',
                                           headers=headers,
                                           body=req_body)

        if resp.status == 200:
            resp_auth = jsonutils.loads(resp_body)['access']
            creds_region = self.creds.get('region')
            if self.configure_via_auth:
                endpoint = get_endpoint(resp_auth['serviceCatalog'],
                                        endpoint_region=creds_region)
                self.management_url = endpoint
            self.auth_token = resp_auth['token']['id']
        elif resp.status == 305:
            raise exceptions.RedirectException(resp['location'])
        elif resp.status == 400:
            raise exceptions.AuthBadRequest(url=token_url)
        elif resp.status == 401:
            raise exceptions.NotAuthenticated()
        elif resp.status == 404:
            raise exceptions.AuthUrlNotFound(url=token_url)
        else:
            raise Exception(_('Unexpected response: %s') % resp.status)
Ejemplo n.º 57
0
    def get_size(self, location, context=None):
        """
        Takes a `glance_store.location.Location` object that indicates
        where to find the image file, and returns the size

        :param location `glance_store.location.Location` object, supplied
                        from glance_store.location.get_location_from_uri()
        :raises `glance_store.exceptions.NotFound` if image does not exist
        """
        loc = location.store_location
        with rados.Rados(conffile=self.conf_file, rados_id=self.user) as conn:
            with conn.open_ioctx(self.pool) as ioctx:
                try:
                    with rbd.Image(ioctx, loc.image,
                                   snapshot=loc.snapshot) as image:
                        img_info = image.stat()
                        return img_info['size']
                except rbd.ImageNotFound:
                    msg = _('RBD image %s does not exist') % loc.get_uri()
                    LOG.debug(msg)
                    raise exceptions.NotFound(msg)
Ejemplo n.º 58
0
    def configure(self, re_raise_bsc=False):
        """
        Configure the store to use the stored configuration options
        and initialize capabilities based on current configuration.

        Any store that needs special configuration should implement
        this method.
        """

        try:
            self.configure_add()
        except exceptions.BadStoreConfiguration as e:
            self.unset_capabilities(capabilities.BitMasks.WRITE_ACCESS)
            msg = (_(u"Failed to configure store correctly: %s "
                     "Disabling add method.") %
                   encodeutils.exception_to_unicode(e))
            LOG.warning(msg)
            if re_raise_bsc:
                raise
        finally:
            self.update_capabilities()
Ejemplo n.º 59
0
    def get_image_file(self, full_data_path):
        """
        Looks for the image on the path specified or raises exception
        """
        try:

            file_object = self.irods_conn_object.data_objects.get(
                full_data_path)

        except:
            msg = _("image file %s not found") % full_data_path
            Log.error(msg)
            raise exceptions.NotFound(msg)

        LOG.debug("path = %(path)s, size = %(data_size)s" %
                  ({
                      'path': full_data_path,
                      'data_size': file_object.size
                  }))

        return file_object, file_object.size
Ejemplo n.º 60
0
    def delete(self, location, context=None):
        """
        Takes a `glance_store.location.Location` object that indicates
        where to find the image file to delete

        :param location: `glance_store.location.Location` object, supplied
                  from glance_store.location.get_location_from_uri()

        :raises: NotFound if image does not exist
        :raises: Forbidden if cannot delete because of permissions
        """
        loc = location.store_location
        self._check_context(context)
        try:
            volume = self.get_cinderclient(context).volumes.get(loc.volume_id)
            volume.delete()
        except cinder_exception.NotFound:
            raise exceptions.NotFound(image=loc.volume_id)
        except cinder_exception.ClientException as e:
            msg = (_('Failed to delete volume %(volume_id)s: %(error)s') %
                   {'volume_id': loc.volume_id, 'error': e})
            raise exceptions.BackendException(msg)