jclouds : how do I update metadata for an existing

2019-06-26 13:04发布

问题:

I've got a few thousand blobs at Rackspace's Cloud Files which I need to update content type for. However, I can't figure out how I do that using the jclouds API.

How can I go about to update metadata on an existing blob?

回答1:

Assuming you have the whole set up running for your rackspace, using jclouds is easy:

First initialize with the following details:

    BlobStoreContext context = ContextBuilder.newBuilder(provider)
            .credentials(username, apiKey)
            .buildView(BlobStoreContext.class);

    BlobStore blobStore = context.getBlobStore();

You can now build a new blob to to put on rackspace:

Blob blob = blobStore.blobBuilder(key) .userMetadata(metadata) .payload(value) .build();

blobStore.putBlob(container, blob);

value is the input bytes[] and metadata is a hash map of meta data associated with the blob like content type.

If you want to do operations like update:

RegionScopedBlobStoreContext context = ContextBuilder.newBuilder("openstack-swift")
                                .endpoint(config.getAuthUrl())
                                .credentials(config.getUser(), config.getPasswd())
                                .overrides(p)
                                .buildView(RegionScopedBlobStoreContext.class);
SwiftApi swift = (SwiftApi) ((org.jclouds.rest.internal.ApiContextImpl)context.unwrap()).getApi();

boolean success = swift.objectApiInRegionForContainer(config.getRegion(), container).updateMetadata(filename, metaData);

I know it is an overview but I hope it gives you a good direction.



回答2:

As of jclouds 2.1.0 (and 1.9.3 at least) the API to change object custom metadata looks like this:

BlobStoreContext context = contextBuilder.buildView(BlobStoreContext.class);
SwiftApi api = (SwiftApi) ((org.jclouds.rest.internal.ApiContextImpl)context.unwrap()).getApi();
ObjectApi objectApi = api.getObjectApi(region, container);
Map<String, String> meta = new HashMap<>();
meta.put('some-meta', value);
objectApi.updateMetadata(blobName, meta);

Content type cannot be updated this way, only metadata with keys starting from X-Object-Meta- can be updated. updateMetadata automatically prefixes all keys passed to it with X-Object-Meta-. In the example above custom data with key X-Object-Meta-some-meta would be added to the blob.

Theoretically updateRawMetadata should be able to update content type (it does not add X-Object-Meta- prefix to keys and passes them verbatim) but due to a bug in jclouds it fails for content type key with error:

configuration error please use request.getPayload().getContentMetadata().setContentType(value) as opposed to adding a content type header

I've checked update content type via curl and it works fine, so it is a bug in jclouds:

curl -X POST -H "X-Auth-Token: $TOKEN" -H "Content-Type: $CONTENT_TYPE"  "$PUBLIC_URL/$CONTAINER/$BLOB_NAME"

The workaround for this is to use copy operation to copy the blob into itself as described in the documentation for the API:

You can use COPY as an alternate to the POST operation by copying to the same object

And this can be done using vendor/api independent jclouds API like this:

Blob blob = blobStore.getBlob(container, blobName);
MutableContentMetadata contentMetadata = blob.getPayload().getContentMetadata();
contentMetadata.setContentType(mimeType);
blobStore.copyBlob(getContainer, blobName, getContainer, blobName,
       CopyOptions.builder().contentMetadata(contentMetadata).build());

Or via SwiftApi (this does not require fetching of the blob's metadata):

BlobStoreContext context = contextBuilder.buildView(BlobStoreContext.class);
SwiftApi api = (SwiftApi) ((org.jclouds.rest.internal.ApiContextImpl)context.unwrap()).getApi();
ObjectApi objectApi = api.getObjectApi(region, container);
Map<String, String> meta = new HashMap<>();
meta.put(HttpHeaders.CONTENT_TYPE, mimeType);
objectApi.copy(blobName, container, blobName, new HashMap<String, String>(), meta);