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?
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?
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.
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);