示例#1
0
    def compose_objects(self,
                        source_resources,
                        destination_resource,
                        request_config=None):
        """See CloudApi class for function doc strings."""

        if not source_resources:
            raise cloud_errors.GcsApiError(
                'Compose requires at least one component object.')

        if len(source_resources) > MAX_OBJECTS_PER_COMPOSE_CALL:
            raise cloud_errors.GcsApiError(
                'Compose was called with {} objects. The limit is {}.'.format(
                    len(source_resources), MAX_OBJECTS_PER_COMPOSE_CALL))

        validated_request_config = cloud_api.get_provider_request_config(
            request_config, GcsRequestConfig)

        source_messages = []
        for source in source_resources:
            source_message = self.messages.ComposeRequest.SourceObjectsValueListEntry(
                name=source.storage_url.object_name)
            if source.storage_url.generation is not None:
                generation = int(source.storage_url.generation)
                source_message.generation = generation
            source_messages.append(source_message)

        compose_request_payload = self.messages.ComposeRequest(
            sourceObjects=source_messages,
            destination=gcs_metadata_util.get_apitools_metadata_from_url(
                destination_resource.storage_url))

        compose_request = self.messages.StorageObjectsComposeRequest(
            composeRequest=compose_request_payload,
            destinationBucket=destination_resource.storage_url.bucket_name,
            destinationObject=destination_resource.storage_url.object_name,
            ifGenerationMatch=(
                validated_request_config.precondition_generation_match),
            ifMetagenerationMatch=(
                validated_request_config.precondition_metageneration_match),
        )

        if validated_request_config.predefined_acl_string is not None:
            compose_request.destinationPredefinedAcl = getattr(
                self.messages.StorageObjectsComposeRequest.
                DestinationPredefinedAclValueValuesEnum,
                request_config.predefined_acl_string)

        return gcs_metadata_util.get_object_resource_from_metadata(
            self.client.objects.Compose(compose_request))
示例#2
0
    def patch_object_metadata(self,
                              bucket_name,
                              object_name,
                              object_resource,
                              fields_scope=cloud_api.FieldsScope.NO_ACL,
                              generation=None,
                              request_config=None):
        """See super class."""
        # S3 requires a string, but GCS uses an int for generation.
        if generation:
            generation = int(generation)

        if not request_config:
            request_config = GcsRequestConfig()

        predefined_acl = None
        if request_config.predefined_acl_string:
            predefined_acl = getattr(
                self.messages.StorageObjectsPatchRequest.
                PredefinedAclValueValuesEnum,
                request_config.predefined_acl_string)

        projection = self._get_projection(
            fields_scope, self.messages.StorageObjectsPatchRequest)

        # Assume parameters are only for identifying what needs to be patched, and
        # the resource contains the desired patched metadata values.
        patched_metadata = object_resource.metadata
        if not patched_metadata:
            object_resource.metadata = gcs_metadata_util.get_apitools_metadata_from_url(
                object_resource.storage_url)

        request = self.messages.StorageObjectsPatchRequest(
            bucket=bucket_name,
            object=object_name,
            objectResource=object_resource.metadata,
            generation=generation,
            ifGenerationMatch=request_config.precondition_generation_match,
            ifMetagenerationMatch=request_config.
            precondition_metageneration_match,
            predefinedAcl=predefined_acl,
            projection=projection)

        updated_metadata = self.client.objects.Patch(request)
        return gcs_metadata_util.get_object_resource_from_metadata(
            updated_metadata)
示例#3
0
    def create_bucket(self,
                      bucket_resource,
                      fields_scope=cloud_api.FieldsScope.NO_ACL):
        """See super class."""
        projection = self._get_projection(
            fields_scope, self.messages.StorageBucketsInsertRequest)
        if not bucket_resource.metadata:
            bucket_resource.metadata = gcs_metadata_util.get_apitools_metadata_from_url(
                bucket_resource.storage_url)

        request = self.messages.StorageBucketsInsertRequest(
            bucket=bucket_resource.metadata,
            project=properties.VALUES.core.project.GetOrFail(),
            projection=projection)

        created_bucket_metadata = self.client.buckets.Insert(request)
        return gcs_metadata_util.get_bucket_resource_from_metadata(
            created_bucket_metadata)
示例#4
0
    def copy_object(self,
                    source_resource,
                    destination_resource,
                    progress_callback=None,
                    request_config=None):
        """See super class."""
        # TODO(b/161898251): Implement encryption and decryption.
        if not request_config:
            request_config = GcsRequestConfig()

        destination_metadata = getattr(destination_resource, 'metadata', None)
        if not destination_metadata:
            destination_metadata = gcs_metadata_util.get_apitools_metadata_from_url(
                destination_resource.storage_url)
            if source_resource.metadata:
                gcs_metadata_util.copy_select_object_metadata(
                    source_resource.metadata, destination_metadata)

        if request_config.max_bytes_per_call:
            max_bytes_per_call = request_config.max_bytes_per_call
        else:
            max_bytes_per_call = scaled_integer.ParseInteger(
                properties.VALUES.storage.copy_chunk_size.Get())

        if request_config.predefined_acl_string:
            predefined_acl = getattr(
                self.messages.StorageObjectsRewriteRequest.
                DestinationPredefinedAclValueValuesEnum,
                request_config.predefined_acl_string)
        else:
            predefined_acl = None

        if source_resource.generation is None:
            source_generation = None
        else:
            source_generation = int(source_resource.generation)

        tracker_file_path = tracker_file_util.get_tracker_file_path(
            destination_resource.storage_url,
            tracker_file_util.TrackerFileType.REWRITE,
            source_resource.storage_url)
        rewrite_parameters_hash = tracker_file_util.hash_gcs_rewrite_parameters_for_tracker_file(
            source_resource,
            destination_resource,
            destination_metadata,
            request_config=request_config)
        try:
            resume_rewrite_token = tracker_file_util.read_rewrite_tracker_file(
                tracker_file_path, rewrite_parameters_hash)
            log.debug('Found rewrite token. Resuming copy.')
        except files.MissingFileError:
            resume_rewrite_token = None
            log.debug('No rewrite token found. Starting copy from scratch.')

        while True:
            request = self.messages.StorageObjectsRewriteRequest(
                sourceBucket=source_resource.storage_url.bucket_name,
                sourceObject=source_resource.storage_url.object_name,
                destinationBucket=destination_resource.storage_url.bucket_name,
                destinationObject=destination_resource.storage_url.object_name,
                object=destination_metadata,
                sourceGeneration=source_generation,
                ifGenerationMatch=request_config.precondition_generation_match,
                ifMetagenerationMatch=(
                    request_config.precondition_metageneration_match),
                destinationPredefinedAcl=predefined_acl,
                rewriteToken=resume_rewrite_token,
                maxBytesRewrittenPerCall=max_bytes_per_call)
            rewrite_response = self.client.objects.Rewrite(request)
            processed_bytes = rewrite_response.totalBytesRewritten
            if progress_callback:
                progress_callback(processed_bytes)

            if rewrite_response.done:
                break
            elif not resume_rewrite_token:
                resume_rewrite_token = rewrite_response.rewriteToken
                tracker_file_util.write_rewrite_tracker_file(
                    tracker_file_path, rewrite_parameters_hash,
                    rewrite_response.rewriteToken)

        tracker_file_util.delete_tracker_file(tracker_file_path)
        return gcs_metadata_util.get_object_resource_from_metadata(
            rewrite_response.resource)
示例#5
0
    def compose_objects(self,
                        source_resources,
                        destination_resource,
                        request_config,
                        original_source_resource=None):
        """See CloudApi class for function doc strings."""

        if not source_resources:
            raise cloud_errors.GcsApiError(
                'Compose requires at least one component object.')

        if len(source_resources) > MAX_OBJECTS_PER_COMPOSE_CALL:
            raise cloud_errors.GcsApiError(
                'Compose was called with {} objects. The limit is {}.'.format(
                    len(source_resources), MAX_OBJECTS_PER_COMPOSE_CALL))

        source_messages = []
        for source in source_resources:
            source_message = self.messages.ComposeRequest.SourceObjectsValueListEntry(
                name=source.storage_url.object_name)
            if source.storage_url.generation is not None:
                generation = int(source.storage_url.generation)
                source_message.generation = generation
            source_messages.append(source_message)

        destination_metadata = gcs_metadata_util.get_apitools_metadata_from_url(
            destination_resource.storage_url)
        if original_source_resource and isinstance(
                original_source_resource,
                resource_reference.FileObjectResource):
            original_source_file_path = (
                original_source_resource.storage_url.object_name)
        else:
            original_source_file_path = None
        gcs_metadata_util.update_object_metadata_from_request_config(
            destination_metadata, request_config, original_source_file_path)

        compose_request_payload = self.messages.ComposeRequest(
            sourceObjects=source_messages, destination=destination_metadata)

        compose_request = self.messages.StorageObjectsComposeRequest(
            composeRequest=compose_request_payload,
            destinationBucket=destination_resource.storage_url.bucket_name,
            destinationObject=destination_resource.storage_url.object_name,
            ifGenerationMatch=request_config.precondition_generation_match,
            ifMetagenerationMatch=request_config.
            precondition_metageneration_match)

        if request_config.resource_args:
            encryption_key = request_config.resource_args.encryption_key
            if encryption_key and encryption_key.type == encryption_util.KeyType.CMEK:
                compose_request.kmsKeyName = encryption_key.key

        if request_config.predefined_acl_string is not None:
            compose_request.destinationPredefinedAcl = getattr(
                self.messages.StorageObjectsComposeRequest.
                DestinationPredefinedAclValueValuesEnum,
                request_config.predefined_acl_string)

        encryption_key = getattr(request_config.resource_args,
                                 'encryption_key', None)
        with self._encryption_headers_context(encryption_key):
            return gcs_metadata_util.get_object_resource_from_metadata(
                self.client.objects.Compose(compose_request))
示例#6
0
    def copy_object(self,
                    source_resource,
                    destination_resource,
                    request_config,
                    progress_callback=None):
        """See super class."""
        destination_metadata = getattr(destination_resource, 'metadata', None)
        if not destination_metadata:
            destination_metadata = gcs_metadata_util.get_apitools_metadata_from_url(
                destination_resource.storage_url)
        if source_resource.metadata:
            gcs_metadata_util.copy_select_object_metadata(
                source_resource.metadata, destination_metadata, request_config)
        gcs_metadata_util.update_object_metadata_from_request_config(
            destination_metadata, request_config)

        if request_config.max_bytes_per_call:
            max_bytes_per_call = request_config.max_bytes_per_call
        else:
            max_bytes_per_call = scaled_integer.ParseInteger(
                properties.VALUES.storage.copy_chunk_size.Get())

        if request_config.predefined_acl_string:
            predefined_acl = getattr(
                self.messages.StorageObjectsRewriteRequest.
                DestinationPredefinedAclValueValuesEnum,
                request_config.predefined_acl_string)
        else:
            predefined_acl = None

        if source_resource.generation is None:
            source_generation = None
        else:
            source_generation = int(source_resource.generation)

        tracker_file_path = tracker_file_util.get_tracker_file_path(
            destination_resource.storage_url,
            tracker_file_util.TrackerFileType.REWRITE,
            source_url=source_resource.storage_url)
        rewrite_parameters_hash = tracker_file_util.hash_gcs_rewrite_parameters_for_tracker_file(
            source_resource,
            destination_resource,
            destination_metadata,
            request_config=request_config)
        try:
            resume_rewrite_token = tracker_file_util.read_rewrite_tracker_file(
                tracker_file_path, rewrite_parameters_hash)
            log.debug('Found rewrite token. Resuming copy.')
        except files.MissingFileError:
            resume_rewrite_token = None
            log.debug('No rewrite token found. Starting copy from scratch.')

        with self._encryption_headers_for_rewrite_call_context(request_config):
            while True:
                request = self.messages.StorageObjectsRewriteRequest(
                    sourceBucket=source_resource.storage_url.bucket_name,
                    sourceObject=source_resource.storage_url.object_name,
                    destinationBucket=destination_resource.storage_url.
                    bucket_name,
                    destinationObject=destination_resource.storage_url.
                    object_name,
                    object=destination_metadata,
                    sourceGeneration=source_generation,
                    ifGenerationMatch=copy_util.get_generation_match_value(
                        request_config),
                    ifMetagenerationMatch=request_config.
                    precondition_metageneration_match,
                    destinationPredefinedAcl=predefined_acl,
                    rewriteToken=resume_rewrite_token,
                    maxBytesRewrittenPerCall=max_bytes_per_call)

                encryption_key = getattr(request_config.resource_args,
                                         'encryption_key', None)
                if encryption_key and encryption_key.type == encryption_util.KeyType.CMEK:
                    # This key is also provided in destination_metadata.kmsKeyName by
                    # update_object_metadata_from_request_config. This has no effect on
                    # the copy object request, which references the field below, and is a
                    # side-effect of logic required for uploads and compose operations.
                    request.destinationKmsKeyName = encryption_key.key

                rewrite_response = self.client.objects.Rewrite(request)
                processed_bytes = rewrite_response.totalBytesRewritten
                if progress_callback:
                    progress_callback(processed_bytes)

                if rewrite_response.done:
                    break

                if not resume_rewrite_token:
                    resume_rewrite_token = rewrite_response.rewriteToken
                    if source_resource.size >= scaled_integer.ParseInteger(
                            properties.VALUES.storage.resumable_threshold.Get(
                            )):
                        tracker_file_util.write_rewrite_tracker_file(
                            tracker_file_path, rewrite_parameters_hash,
                            rewrite_response.rewriteToken)

        tracker_file_util.delete_tracker_file(tracker_file_path)
        return gcs_metadata_util.get_object_resource_from_metadata(
            rewrite_response.resource)