def _upload_image(
        self,
        name,
        filename,
        data,
        meta,
        wait,
        timeout,
        use_import=False,
        stores=None,
        all_stores=None,
        all_stores_must_succeed=None,
        **image_kwargs,
    ):
        if use_import:
            raise exceptions.InvalidRequest(
                "Glance v1 does not support image import")
        if stores or all_stores or all_stores_must_succeed:
            raise exceptions.InvalidRequest(
                "Glance v1 does not support stores")
        # NOTE(mordred) wait and timeout parameters are unused, but
        # are present for ease at calling site.
        if filename and not data:
            image_data = open(filename, 'rb')
        else:
            image_data = data
        image_kwargs['properties'].update(meta)
        image_kwargs['name'] = name

        # TODO(mordred) Convert this to use image Resource
        image = self._connection._get_and_munchify(
            'image', self.post('/images', json=image_kwargs))
        checksum = image_kwargs['properties'].get(self._IMAGE_MD5_KEY, '')

        try:
            # Let us all take a brief moment to be grateful that this
            # is not actually how OpenStack APIs work anymore
            headers = {
                'x-glance-registry-purge-props': 'false',
            }
            if checksum:
                headers['x-image-meta-checksum'] = checksum

            image = self._connection._get_and_munchify(
                'image',
                self.put('/images/{id}'.format(id=image.id),
                         headers=headers,
                         data=image_data))

        except exc.OpenStackCloudHTTPError:
            self.log.debug("Deleting failed upload of image %s", name)
            try:
                self.delete('/images/{id}'.format(id=image.id))
            except exc.OpenStackCloudHTTPError:
                # We're just trying to clean up - if it doesn't work - shrug
                self.log.warning(
                    "Failed deleting image after we failed uploading it.",
                    exc_info=True)
            raise
        return self._connection._normalize_image(image)
    def role_assignments_filter(self, domain=None, project=None, group=None,
                                user=None):
        """Retrieve a generator of roles assigned to user/group

        :param domain: Either the ID of a domain or a
                      :class:`~openstack.identity.v3.domain.Domain` instance.
        :param project: Either the ID of a project or a
                      :class:`~openstack.identity.v3.project.Project`
                      instance.
        :param group: Either the ID of a group or a
                      :class:`~openstack.identity.v3.group.Group` instance.
        :param user: Either the ID of a user or a
                     :class:`~openstack.identity.v3.user.User` instance.
        :return: A generator of role instances.
        :rtype: :class:`~openstack.identity.v3.role.Role`
        """
        if domain and project:
            raise exception.InvalidRequest(
                'Only one of domain or project can be specified')

        if domain is None and project is None:
            raise exception.InvalidRequest(
                'Either domain or project should be specified')

        if group and user:
            raise exception.InvalidRequest(
                'Only one of group or user can be specified')

        if group is None and user is None:
            raise exception.InvalidRequest(
                'Either group or user should be specified')

        if domain:
            domain = self._get_resource(_domain.Domain, domain)
            if group:
                group = self._get_resource(_group.Group, group)
                return self._list(
                    _role_domain_group_assignment.RoleDomainGroupAssignment,
                    paginated=False, domain_id=domain.id, group_id=group.id)
            else:
                user = self._get_resource(_user.User, user)
                return self._list(
                    _role_domain_user_assignment.RoleDomainUserAssignment,
                    paginated=False, domain_id=domain.id, user_id=user.id)
        else:
            project = self._get_resource(_project.Project, project)
            if group:
                group = self._get_resource(_group.Group, group)
                return self._list(
                    _role_project_group_assignment.RoleProjectGroupAssignment,
                    paginated=False, project_id=project.id, group_id=group.id)
            else:
                user = self._get_resource(_user.User, user)
                return self._list(
                    _role_project_user_assignment.RoleProjectUserAssignment,
                    paginated=False, project_id=project.id, user_id=user.id)
Example #3
0
    def _prepare_request(self, requires_id=True, prepend_key=False):
        """Prepare a request to be sent to the server

        Create operations don't require an ID, but all others do,
        so only try to append an ID when it's needed with
        requires_id. Create and update operations sometimes require
        their bodies to be contained within an dict -- if the
        instance contains a resource_key and prepend_key=True,
        the body will be wrapped in a dict with that key.

        Return a _Request object that contains the constructed URI
        as well a body and headers that are ready to send.
        Only dirty body and header contents will be returned.
        """
        body = self._body.dirty
        if prepend_key and self.resource_key is not None:
            body = {self.resource_key: body}

        headers = self._header.dirty

        uri = self.base_path % self._uri.attributes
        if requires_id:
            if self.id is None:
                raise exceptions.InvalidRequest(
                    "Request requires an ID but none was found")

            uri = utils.urljoin(uri, self.id)

        return _Request(uri, body, headers)
Example #4
0
    def _prepare_request(self, requires_id=None, prepend_key=False,
                         patch=False, base_path=None, params=None, **kwargs):
        """Prepare a request to be sent to the server

        Create operations don't require an ID, but all others do,
        so only try to append an ID when it's needed with
        requires_id. Create and update operations sometimes require
        their bodies to be contained within an dict -- if the
        instance contains a resource_key and prepend_key=True,
        the body will be wrapped in a dict with that key.
        If patch=True, a JSON patch is prepared instead of the full body.

        Return a _Request object that contains the constructed URI
        as well a body and headers that are ready to send.
        Only dirty body and header contents will be returned.
        """
        if requires_id is None:
            requires_id = self.requires_id

        body = self._prepare_request_body(patch, prepend_key)
        headers = {}

        if base_path is None:
            base_path = self.base_path
        uri = base_path % self._uri.attributes
        if requires_id:
            if self.id is None:
                raise exceptions.InvalidRequest(
                    "Request requires an ID but none was found")

            uri = utils.urljoin(uri, self.id)

        uri = utils.urljoin(self.location.project['id'], uri)

        return resource._Request(uri, body, headers)
Example #5
0
    def validate_template(self, template, environment=None, template_url=None,
                          ignore_errors=None):
        """Validates a template.

        :param template: The stack template on which the validation is
                         performed.
        :param environment: A JSON environment for the stack, if provided.
        :param template_url: A URI to the location containing the stack
                             template for validation. This parameter is only
                             required if the ``template`` parameter is None.
                             This parameter is ignored if ``template`` is
                             specified.
        :param ignore_errors: A string containing comma separated error codes
                              to ignore. Currently the only valid error code
                              is '99001'.
        :returns: The result of template validation.
        :raises: :class:`~openstack.exceptions.InvalidRequest` if neither
                 `template` not `template_url` is provided.
        :raises: :class:`~openstack.exceptions.HttpException` if the template
                 fails the validation.
        """
        if template is None and template_url is None:
            raise exceptions.InvalidRequest(
                "'template_url' must be specified when template is None")

        tmpl = _template.Template.new()
        return tmpl.validate(self._session, template, environment=environment,
                             template_url=template_url,
                             ignore_errors=ignore_errors)
Example #6
0
    def delete_host(self, host, segment_id=None, ignore_missing=True):
        """Delete the host.

        :param segment_id: The ID of a failover segment.
        :param host: The value can be the ID of a host or a :class:
                     `~masakariclient.sdk.ha.v1.host.Host` instance.
        :param bool ignore_missing: When set to ``False``
                    :class:`~openstack.exceptions.ResourceNotFound` will be
                    raised when the host does not exist.
                    When set to ``True``, no exception will be set when
                    attempting to delete a nonexistent host.

        :returns: ``None``
        :raises: :class:`~openstack.exceptions.ResourceNotFound`
                 when no resource can be found.
        :raises: :class:`~openstack.exceptions.InvalidRequest`
                 when segment_id is None.

        """
        if segment_id is None:
            raise exceptions.InvalidRequest("'segment_id' must be specified.")

        host_id = resource.Resource._get_id(host)
        return self._delete(_host.Host, host_id, segment_id=segment_id,
                            ignore_missing=ignore_missing)
Example #7
0
    def import_image(self, image, method='glance-direct', uri=None):
        """Import data to an existing image

        Interoperable image import process are introduced in the Image API
        v2.6. It mainly allow image importing from an external url and let
        Image Service download it by itself without sending binary data at
        image creation.

        :param image: The value can be the ID of a image or a
                      :class:`~openstack.image.v2.image.Image` instance.
        :param method: Method to use for importing the image.
                       A valid value is glance-direct or web-download.
        :param uri: Required only if using the web-download import method.
                    This url is where the data is made available to the Image
                    service.

        :returns: None
        """
        image = self._get_resource(_image.Image, image)

        # as for the standard image upload function, container_format and
        # disk_format are required for using image import process
        if not all([image.container_format, image.disk_format]):
            raise exceptions.InvalidRequest(
                "Both container_format and disk_format are required for"
                " importing an image")

        image.import_image(self, method=method, uri=uri)
    def import_image(self,
                     session,
                     method='glance-direct',
                     uri=None,
                     store=None,
                     stores=None,
                     all_stores=None,
                     all_stores_must_succeed=None):
        """Import Image via interoperable image import process"""
        if all_stores and (store or stores):
            raise exceptions.InvalidRequest(
                "all_stores is mutually exclusive with"
                " store and stores")
        if store and stores:
            raise exceptions.InvalidRequest(
                "store and stores are mutually exclusive."
                " Please just use stores.")
        if store:
            stores = [store]
        else:
            stores = stores or []

        url = utils.urljoin(self.base_path, self.id, 'import')
        json = {'method': {'name': method}}
        if uri:
            if method == 'web-download':
                json['method']['uri'] = uri
            else:
                raise exceptions.InvalidRequest('URI is only supported with '
                                                'method: "web-download"')
        if all_stores is not None:
            json['all_stores'] = all_stores
        if all_stores_must_succeed is not None:
            json['all_stores_must_succeed'] = all_stores_must_succeed
        for s in stores:
            json.setdefault('stores', [])
            json['stores'].append(s.id)

        headers = {}
        # Backward compat
        if store is not None:
            headers = {'X-Image-Meta-Store': store.id}
        session.post(url, json=json, headers=headers)
Example #9
0
 def import_image(self, session, method='glance-direct', uri=None):
     """Import Image via interoperable image import process"""
     url = utils.urljoin(self.base_path, self.id, 'import')
     json = {'method': {'name': method}}
     if uri:
         if method == 'web-download':
             json['method']['uri'] = uri
         else:
             raise exceptions.InvalidRequest('URI is only supported with '
                                             'method: "web-download"')
     session.post(url, json=json)
Example #10
0
 def __init__(self, debug=False):
     utils.enable_logging(debug=debug, stream=sys.stdout)
     try:
         self.conn = connection.Connection(auth_url=self.auth_url,
                                           user_domain_id=self.userDomainId,
                                           project_id=self.projectId,
                                           username=self.username,
                                           password=self.password,
                                           verify=False)
     except _exceptions.InvalidRequest as e:
         raise _exceptions.InvalidRequest(message='init connect error')
Example #11
0
    def _prepare_request(self, requires_id=False, prepend_key=False):
        body = self._body.dirty
        if prepend_key and self.resource_key is not None:
            body = {self.resource_key: body}
        headers = self._header.dirty
        if requires_id:
            if self.id is None:
                raise exceptions.InvalidRequest(
                    "Request requires an ID but none was found")
            uri = utils.urljoin(self.base_path, self.id)

        return _Request(uri, body, headers)
Example #12
0
    def upload_image(self,
                     container_format=None,
                     disk_format=None,
                     data=None,
                     **attrs):
        """Create and upload a new image from attributes

        .. warning:
          This method is deprecated - and also doesn't work very well.
          Please stop using it immediately and switch to
          `create_image`.

        :param container_format: Format of the container.
                                 A valid value is ami, ari, aki, bare,
                                 ovf, ova, or docker.
        :param disk_format: The format of the disk. A valid value is ami,
                            ari, aki, vhd, vmdk, raw, qcow2, vdi, or iso.
        :param data: The data to be uploaded as an image.
        :param dict attrs: Keyword arguments which will be used to create
                           a :class:`~openstack.image.v2.image.Image`,
                           comprised of the properties on the Image class.

        :returns: The results of image creation
        :rtype: :class:`~openstack.image.v2.image.Image`
        """
        warnings.warn("upload_image is deprecated. Use create_image instead.")
        # container_format and disk_format are required to be set
        # on the image by the time upload_image is called, but they're not
        # required by the _create call. Enforce them here so that we don't
        # need to handle a failure in _create, as upload_image will
        # return a 400 with a message about disk_format and container_format
        # not being set.
        if not all([container_format, disk_format]):
            raise exceptions.InvalidRequest(
                "Both container_format and disk_format are required")

        img = self._create(_image.Image,
                           disk_format=disk_format,
                           container_format=container_format,
                           **attrs)

        # TODO(briancurtin): Perhaps we should run img.upload_image
        # in a background thread and just return what is called by
        # self._create, especially because the upload_image call doesn't
        # return anything anyway. Otherwise this blocks while uploading
        # significant amounts of image data.
        img.data = data
        img.upload(self)

        return img
Example #13
0
    def tag_action(self, session, **attrs):
        if not self.allow_create:
            raise exceptions.MethodNotSupported(self, "create")

        request = self._prepare_request(requires_id=False)
        endpoint_override = self.service.get_endpoint_override()
        #super(TagAction, self).create(session, )
        response = session.post(request.uri, endpoint_filter=self.service,
                                endpoint_override=endpoint_override,
                                json=attrs, headers=request.headers)

        if not response.status_code == 204:
            _logger.debug(
                'request AS service tag action url is %s response code is %s ' % (response.url, response.status_code))
            raise exceptions.InvalidRequest(
                "Request AS service tag action %s failed" % request.uri)
        else:
            return self
Example #14
0
    def delete_notification(self, session):
        request = self._prepare_request(requires_id=False)
        endpoint_override = self.service.get_endpoint_override()

        response = session.delete(request.uri,
                                  endpoint_filter=self.service,
                                  endpoint_override=endpoint_override,
                                  headers=request.headers)

        if not response.status_code == 204:
            _logger.debug(
                'failed request AS service delete notification url is %s response code is %s '
                % (response.url, response.status_code))
            raise exceptions.InvalidRequest(
                "Request AS service delete notification %s failed" %
                request.uri)
        else:
            return self
Example #15
0
    def get_host(self, host, segment_id=None):
        """Get a single host.

        :param segment_id: The ID of a failover segment.
        :param host: The value can be the ID of a host or a :class:
                     `~masakariclient.sdk.ha.v1.host.Host` instance.

        :returns: One :class:`~masakariclient.sdk.ha.v1.host.Host`
        :raises: :class:`~openstack.exceptions.ResourceNotFound`
                 when no resource can be found.
        :raises: :class:`~openstack.exceptions.InvalidRequest`
                 when segment_id is None.
        """
        if segment_id is None:
            raise exceptions.InvalidRequest("'segment_id' must be specified.")

        host_id = resource.Resource._get_id(host)
        return self._get(_host.Host, host_id, segment_id=segment_id)
Example #16
0
    def call_back(self, session, **attrs):
        request = self._prepare_request(requires_id=False)
        endpoint_override = self.service.get_endpoint_override()

        response = session.put(request.uri,
                               endpoint_filter=self.service,
                               endpoint_override=endpoint_override,
                               json=attrs,
                               headers=request.headers)

        if not response.status_code == 204:
            _logger.debug(
                'request AS service lifecycle hook call back url is %s response code is %s '
                % (response.url, response.status_code))
            raise exceptions.InvalidRequest(
                "Request AS service lifecycle hook call back %s failed" %
                request.uri)
        else:
            return self
Example #17
0
    def _prepare_request(self, requires_id=True, prepend_key=False):
        body = self._body.dirty
        if prepend_key and self.resource_key is not None:
            body = {self.resource_key: body}

        headers = self._header.dirty

        headers.update({'Content-type': 'application/json'})
        # Notes: take cares for create/put, need Content-Length in headers
        if requires_id is False or len(body) == 0:
            headers.update({'Content-Length': str(len(str(body)))})
        uri = self.base_path % self._uri.attributes
        if requires_id:
            if self.id is None:
                raise exceptions.InvalidRequest(
                    "Request requires an ID but none was found")

            uri = utils.urljoin(uri, self.id)

        return resource._Request(uri, body, headers)
Example #18
0
    def _prepare_request(self, requires_id=True, prepend_key=False):
        body = self._body.dirty
        if prepend_key and self.resource_key is not None:
            body = {self.resource_key: body}

        headers = self._header.dirty

        headers.update({
            'Content-type': 'application/json',
            'X-Language': 'en-us'
        })

        uri = self.base_path % self._uri.attributes
        if requires_id:
            if self.id is None:
                raise exceptions.InvalidRequest(
                    "Request requires an ID but none was found")

            uri = utils.urljoin(uri, self.id)

        return resource._Request(uri, body, headers)
Example #19
0
    def list(cls, session, paginated=False, **params):
        """This method is a generator which yields resource objects.

        This resource object list generator handles pagination and takes query
        params for response filtering.

        :param session: The session to use for making this request.
        :type session: :class:`~openstack.session.Session`
        :param bool paginated: ``True`` if a GET to this resource returns
                               a paginated series of responses, or ``False``
                               if a GET returns only one page of data.
                               **When paginated is False only one
                               page of data will be returned regardless
                               of the API's support of pagination.**
        :param dict params: These keyword arguments are passed through the
            :meth:`~openstack.resource2.QueryParamter._transpose` method
            to find if any of them match expected query parameters to be
            sent in the *params* argument to
            :meth:`~openstack.session.Session.get`. They are additionally
            checked against the
            :data:`~openstack.resource2.Resource.base_path` format string
            to see if any path fragments need to be filled in by the contents
            of this argument.

        :return: A generator of :class:`Resource` objects.
        :raises: :exc:`~openstack.exceptions.MethodNotSupported` if
                 :data:`Resource.allow_list` is not set to ``True``.
        """
        if not cls.allow_list:
            raise exceptions.MethodNotSupported(cls, "list")

        more_data = True
        query_params = cls._query_mapping._transpose(params)
        if cls.query_page_size_key and \
                cls.query_page_size_key not in query_params:
            raise exceptions.InvalidRequest('query parameter %s is required.' %
                                            cls.query_page_size_key)
        if cls.query_page_number_key and \
                cls.query_page_number_key not in query_params:
            raise exceptions.InvalidRequest('query parameter %s is required.' %
                                            cls.query_page_number_key)
        uri = cls.get_list_uri(params)

        while more_data:
            endpoint_override = cls.service.get_endpoint_override()
            resp = session.get(uri,
                               endpoint_filter=cls.service,
                               endpoint_override=endpoint_override,
                               headers={"Accept": "application/json"},
                               params=query_params)
            response_json = resp.json()
            cls.check_error(response_json)
            if cls.resources_key:
                resources = cls.find_value_by_accessor(response_json,
                                                       cls.resources_key)
            else:
                resources = response_json
            if resources is None:
                resources = []

            if not resources:
                return

            for data in resources:
                value = cls.existing(**data)
                yield value

            if not paginated:
                return
            more_data, next_page_num = cls.get_next_pagination(
                response_json, query_params)
            query_params[cls.query_page_number_key] = next_page_num
Example #20
0
    def import_image(
        self,
        image,
        method='glance-direct',
        uri=None,
        store=None,
        stores=None,
        all_stores=None,
        all_stores_must_succeed=None,
    ):
        """Import data to an existing image

        Interoperable image import process are introduced in the Image API
        v2.6. It mainly allow image importing from an external url and let
        Image Service download it by itself without sending binary data at
        image creation.

        :param image:
            The value can be the ID of a image or a
            :class:`~openstack.image.v2.image.Image` instance.
        :param method:
            Method to use for importing the image.
            A valid value is glance-direct or web-download.
        :param uri:
            Required only if using the web-download import method.
            This url is where the data is made available to the Image
            service.
        :param store:
            Used when enabled_backends is activated in glance. The value
            can be the id of a store or a
            :class:`~openstack.image.v2.service_info.Store` instance.
        :param stores:
            List of stores to be used when enabled_backends is activated
            in glance. List values can be the id of a store or a
            :class:`~openstack.image.v2.service_info.Store` instance.
        :param all_stores:
            Upload to all available stores. Mutually exclusive with
            ``store`` and ``stores``.
        :param all_stores_must_succeed:
            When set to True, if an error occurs during the upload in at
            least one store, the worfklow fails, the data is deleted
            from stores where copying is done (not staging), and the
            state of the image is unchanged. When set to False, the
            workflow will fail (data deleted from stores, …) only if the
            import fails on all stores specified by the user. In case of
            a partial success, the locations added to the image will be
            the stores where the data has been correctly uploaded.
            Default is True.

        :returns: None
        """
        image = self._get_resource(_image.Image, image)
        if all_stores and (store or stores):
            raise exceptions.InvalidRequest(
                "all_stores is mutually exclusive with"
                " store and stores")
        if store is not None:
            if stores:
                raise exceptions.InvalidRequest(
                    "store and stores are mutually exclusive")
            store = self._get_resource(_si.Store, store)

        stores = stores or []
        new_stores = []
        for s in stores:
            new_stores.append(self._get_resource(_si.Store, s))
        stores = new_stores

        # as for the standard image upload function, container_format and
        # disk_format are required for using image import process
        if not all([image.container_format, image.disk_format]):
            raise exceptions.InvalidRequest(
                "Both container_format and disk_format are required for"
                " importing an image")

        image.import_image(
            self,
            method=method,
            uri=uri,
            store=store,
            stores=stores,
            all_stores=all_stores,
            all_stores_must_succeed=all_stores_must_succeed,
        )