Added the jclouds durability code sample
Added the durability code sample for jclouds and modified the durability chapter to reference it. Change-Id: Id177f18d4bc36642922d7196cde46adf71f20de6 Partial-Bug: #1449330
This commit is contained in:
parent
8c93cdaf67
commit
b50a4acc1f
280
firstapp/samples/jclouds/Durability.java
Normal file
280
firstapp/samples/jclouds/Durability.java
Normal file
@ -0,0 +1,280 @@
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.io.ByteSource;
|
||||
import com.google.common.io.Closeables;
|
||||
import com.google.common.io.Files;
|
||||
import com.google.gson.Gson;
|
||||
import org.jclouds.ContextBuilder;
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.domain.Blob;
|
||||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.io.Payload;
|
||||
import org.jclouds.io.Payloads;
|
||||
import org.jclouds.openstack.swift.v1.SwiftApi;
|
||||
import org.jclouds.openstack.swift.v1.blobstore.RegionScopedBlobStoreContext;
|
||||
import org.jclouds.openstack.swift.v1.domain.Container;
|
||||
import org.jclouds.openstack.swift.v1.domain.SwiftObject;
|
||||
import org.jclouds.openstack.swift.v1.features.ContainerApi;
|
||||
import org.jclouds.openstack.swift.v1.features.ObjectApi;
|
||||
import org.jclouds.openstack.swift.v1.options.CreateContainerOptions;
|
||||
import org.jclouds.openstack.swift.v1.options.PutOptions;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.collect.Iterables.getOnlyElement;
|
||||
import static java.lang.System.out;
|
||||
import static org.jclouds.io.Payloads.newFilePayload;
|
||||
import static org.jclouds.io.Payloads.newInputStreamPayload;
|
||||
|
||||
public class Durability implements Closeable {
|
||||
|
||||
// step-1
|
||||
private final SwiftApi swiftApi;
|
||||
private final String region;
|
||||
private static final String PROVIDER = "openstack-swift";
|
||||
|
||||
private static final String OS_AUTH_URL = "http://controller:5000/v2.0/";
|
||||
// format for identity is projectName:userName
|
||||
private static final String IDENTITY = "your_project_name:your_auth_username";
|
||||
private static final String PASSWORD = "your_auth_password";
|
||||
|
||||
|
||||
public Durability() {
|
||||
swiftApi = ContextBuilder.newBuilder(PROVIDER)
|
||||
.endpoint(OS_AUTH_URL)
|
||||
.credentials(IDENTITY, PASSWORD)
|
||||
.buildApi(SwiftApi.class);
|
||||
region = swiftApi.getConfiguredRegions().iterator().next();
|
||||
out.println("Running in region: " + region);
|
||||
}
|
||||
|
||||
// step-2
|
||||
private void createContainer(String containerName) {
|
||||
ContainerApi containerApi = swiftApi.getContainerApi(region);
|
||||
if (containerApi.create(containerName)) {
|
||||
out.println("Created container: " + containerName);
|
||||
} else {
|
||||
out.println("Container all ready exists: " + containerName);
|
||||
}
|
||||
}
|
||||
|
||||
// step-3
|
||||
private void listContainers() {
|
||||
out.println("Containers:");
|
||||
ContainerApi containerApi = swiftApi.getContainerApi(region);
|
||||
containerApi.list().forEach(container -> out.println(" " + container));
|
||||
}
|
||||
|
||||
// step-4
|
||||
private String uploadObject(String containerName, String objectName, String filePath) {
|
||||
Payload payload = newFilePayload(new File(filePath));
|
||||
ObjectApi objectApi = swiftApi.getObjectApi(region, containerName);
|
||||
String eTag = objectApi.put(objectName, payload);
|
||||
out.println(String.format("Uploaded %s as \"%s\" eTag = %s", filePath, objectName, eTag));
|
||||
return eTag;
|
||||
}
|
||||
|
||||
// step-5
|
||||
private void listObjectsInContainer(String containerName) {
|
||||
out.println("Objects in " + containerName + ":");
|
||||
ObjectApi objectApi = swiftApi.getObjectApi(region, containerName);
|
||||
objectApi.list().forEach(object -> out.println(" " + object));
|
||||
}
|
||||
|
||||
// step-6
|
||||
private SwiftObject getObjectFromContainer(String containerName, String objectName) {
|
||||
ObjectApi objectApi = swiftApi.getObjectApi(region, containerName);
|
||||
SwiftObject object = objectApi.get(objectName);
|
||||
out.println("Fetched: " + object.getName());
|
||||
return object;
|
||||
}
|
||||
|
||||
// step-7
|
||||
private void calculateMd5ForFile(String filePath) {
|
||||
try (FileInputStream fis = new FileInputStream(new File(filePath))) {
|
||||
MessageDigest md5Digest = MessageDigest.getInstance("MD5");
|
||||
|
||||
byte[] byteArray = new byte[1024];
|
||||
int bytesCount;
|
||||
while ((bytesCount = fis.read(byteArray)) != -1) {
|
||||
md5Digest.update(byteArray, 0, bytesCount);
|
||||
}
|
||||
byte[] digest = md5Digest.digest();
|
||||
|
||||
// Convert decimal number to hex string
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte aByte : digest) {
|
||||
sb.append(Integer.toString((aByte & 0xff) + 0x100, 16).substring(1));
|
||||
}
|
||||
|
||||
out.println("MD5 for file " + filePath + ": " + sb.toString());
|
||||
} catch (IOException | NoSuchAlgorithmException e) {
|
||||
out.println("Could not calculate md5: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// step-8
|
||||
private void deleteObject(String containerName, String objectName) {
|
||||
ObjectApi objectApi = swiftApi.getObjectApi(region, containerName);
|
||||
objectApi.delete(objectName);
|
||||
out.println("Deleted: " + objectName);
|
||||
}
|
||||
|
||||
// step-10
|
||||
private Container getContainer(String containerName) {
|
||||
ContainerApi containerApi = swiftApi.getContainerApi(region);
|
||||
// ensure container exists
|
||||
containerApi.create(containerName);
|
||||
return containerApi.get(containerName);
|
||||
}
|
||||
|
||||
// step-11
|
||||
static class Fractal {
|
||||
// only included elements we want to work with
|
||||
String uuid;
|
||||
}
|
||||
|
||||
static class Fractals {
|
||||
// only included elements we want to work with
|
||||
List<Fractal> objects;
|
||||
}
|
||||
|
||||
private void backupFractals(String containerName, String fractalsIp) {
|
||||
// just need to make sure that there is container
|
||||
getContainer(containerName);
|
||||
try {
|
||||
String response = "";
|
||||
String endpoint = "http://" + fractalsIp + "/v1/fractal";
|
||||
URLConnection connection = new URL(endpoint).openConnection();
|
||||
connection.setRequestProperty("'results_per_page", "-1");
|
||||
connection.getInputStream();
|
||||
try (BufferedReader in = new BufferedReader(new InputStreamReader(
|
||||
connection.getInputStream()))) {
|
||||
String inputLine;
|
||||
while ((inputLine = in.readLine()) != null) {
|
||||
response = response + inputLine;
|
||||
}
|
||||
}
|
||||
|
||||
Gson gson = new Gson();
|
||||
Fractals fractals = gson.fromJson(response, Fractals.class);
|
||||
ObjectApi objectApi = swiftApi.getObjectApi(region, containerName);
|
||||
fractals.objects.forEach(fractal -> {
|
||||
try {
|
||||
String fractalEndpoint = "http://" + fractalsIp + "/fractal/" + fractal.uuid;
|
||||
URLConnection conn = new URL(fractalEndpoint).openConnection();
|
||||
try (InputStream inputStream = conn.getInputStream()) {
|
||||
Payload payload = newInputStreamPayload(inputStream);
|
||||
String eTag = objectApi.put(fractal.uuid, payload);
|
||||
out.println(String.format("Backed up %s eTag = %s", fractal.uuid, eTag));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
out.println("Could not backup " + fractal.uuid + "! Cause: " + e.getMessage());
|
||||
}
|
||||
});
|
||||
out.println("Backed up:");
|
||||
objectApi.list().forEach(object -> out.println(" " + object));
|
||||
} catch (IOException e) {
|
||||
out.println("Could not backup fractals! Cause: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// step-12
|
||||
private boolean deleteContainer(String containerName) {
|
||||
ObjectApi objectApi = swiftApi.getObjectApi(region, containerName);
|
||||
objectApi.list().forEach(object -> objectApi.delete(object.getName()));
|
||||
ContainerApi containerApi = swiftApi.getContainerApi(region);
|
||||
return containerApi.deleteIfEmpty(containerName);
|
||||
}
|
||||
|
||||
// step-13
|
||||
private void createWithMetadata(String containerName, String objectName, String filePath) {
|
||||
|
||||
ContainerApi containerApi = swiftApi.getContainerApi(region);
|
||||
CreateContainerOptions options = CreateContainerOptions.Builder
|
||||
.metadata(ImmutableMap.of("photos", "of fractals"));
|
||||
|
||||
if (containerApi.create(containerName, options)) {
|
||||
out.println("Uploading: " + objectName);
|
||||
|
||||
ObjectApi objectApi = swiftApi.getObjectApi(region, containerName);
|
||||
Payload payload = newFilePayload(new File(filePath));
|
||||
PutOptions putOptions = PutOptions.Builder
|
||||
.metadata(ImmutableMap.of(
|
||||
"description", "a funny goat",
|
||||
"created", "2015-06-02"));
|
||||
String eTag = objectApi.put(objectName, payload, putOptions);
|
||||
out.println(
|
||||
String.format("Uploaded %s as \"%s\" eTag = %s", filePath, objectName, eTag));
|
||||
} else {
|
||||
out.println("Could not upload " + objectName);
|
||||
}
|
||||
}
|
||||
|
||||
// step-14
|
||||
private void uploadLargeFile(String containerName, String pathNameOfLargeFile) {
|
||||
// Only works with jclouds V2 (in beta at the time of writing). See:
|
||||
// https://issues.apache.org/jira/browse/JCLOUDS-894
|
||||
try {
|
||||
RegionScopedBlobStoreContext context = ContextBuilder.newBuilder(PROVIDER)
|
||||
.credentials(IDENTITY, PASSWORD)
|
||||
.endpoint(OS_AUTH_URL)
|
||||
.buildView(RegionScopedBlobStoreContext.class);
|
||||
String region = context.getConfiguredRegions().iterator().next();
|
||||
out.println("Running in region: " + region);
|
||||
BlobStore blobStore = context.getBlobStore(region);
|
||||
// create the container if it doesn't exist...
|
||||
Location location = getOnlyElement(blobStore.listAssignableLocations());
|
||||
blobStore.createContainerInLocation(location, containerName);
|
||||
File largeFile = new File(pathNameOfLargeFile);
|
||||
ByteSource source = Files.asByteSource(largeFile);
|
||||
Payload payload = Payloads.newByteSourcePayload(source);
|
||||
payload.getContentMetadata().setContentLength(largeFile.length());
|
||||
out.println("Uploading file. This may take some time!");
|
||||
Blob blob = blobStore.blobBuilder(largeFile.getName())
|
||||
.payload(payload)
|
||||
.build();
|
||||
org.jclouds.blobstore.options.PutOptions putOptions =
|
||||
new org.jclouds.blobstore.options.PutOptions();
|
||||
|
||||
String eTag = blobStore.putBlob(containerName, blob, putOptions.multipart());
|
||||
out.println(String.format("Uploaded %s eTag=%s", largeFile.getName(), eTag));
|
||||
} catch (UnsupportedOperationException e) {
|
||||
out.println("Sorry: large file uploads only work in jclouds V2...");
|
||||
}
|
||||
}
|
||||
|
||||
// step-15
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
Closeables.close(swiftApi, true);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
try (Durability tester = new Durability()) {
|
||||
String containerName = "fractals";
|
||||
String objectName = "an amazing goat";
|
||||
String goatImageFilePath = "goat.jpg";
|
||||
String fractalsIp = "IP_API_1";
|
||||
String pathNameOfLargeFile = "big.img";
|
||||
|
||||
tester.createContainer(containerName);
|
||||
tester.listContainers();
|
||||
tester.uploadObject(containerName, objectName, goatImageFilePath);
|
||||
tester.listObjectsInContainer(containerName);
|
||||
tester.getObjectFromContainer(containerName, objectName);
|
||||
tester.calculateMd5ForFile(goatImageFilePath);
|
||||
tester.deleteObject(containerName, objectName);
|
||||
tester.getContainer(containerName);
|
||||
tester.backupFractals(containerName, fractalsIp);
|
||||
tester.deleteContainer(containerName);
|
||||
tester.createWithMetadata(containerName, objectName, goatImageFilePath);
|
||||
tester.listContainers();
|
||||
tester.uploadLargeFile("largeObject", pathNameOfLargeFile);
|
||||
}
|
||||
}
|
||||
}
|
@ -75,10 +75,12 @@ First, learn how to connect to the Object Storage endpoint:
|
||||
:start-after: step-1
|
||||
:end-before: step-2
|
||||
|
||||
|
||||
.. only:: jclouds
|
||||
|
||||
.. warning:: This section has not yet been completed for the jclouds SDK.
|
||||
.. literalinclude:: ../samples/jclouds/Durability.java
|
||||
:language: java
|
||||
:start-after: step-1
|
||||
:end-before: step-2
|
||||
|
||||
.. only:: libcloud
|
||||
|
||||
@ -131,6 +133,13 @@ Call yours :code:`fractals`:
|
||||
|
||||
TBC
|
||||
|
||||
.. only:: jclouds
|
||||
|
||||
.. literalinclude:: ../samples/jclouds/Durability.java
|
||||
:language: java
|
||||
:start-after: step-2
|
||||
:end-before: step-3
|
||||
|
||||
.. only:: libcloud
|
||||
|
||||
.. literalinclude:: ../samples/libcloud/durability.py
|
||||
@ -158,6 +167,13 @@ all containers in your account:
|
||||
|
||||
TBC
|
||||
|
||||
.. only:: jclouds
|
||||
|
||||
.. literalinclude:: ../samples/jclouds/Durability.java
|
||||
:language: java
|
||||
:start-after: step-3
|
||||
:end-before: step-4
|
||||
|
||||
.. only:: libcloud
|
||||
|
||||
.. literalinclude:: ../samples/libcloud/durability.py
|
||||
@ -180,6 +196,13 @@ on line, name it :code:`goat.jpg`, and upload it to your
|
||||
:start-after: step-4
|
||||
:end-before: step-5
|
||||
|
||||
.. only:: jclouds
|
||||
|
||||
.. literalinclude:: ../samples/jclouds/Durability.java
|
||||
:language: java
|
||||
:start-after: step-4
|
||||
:end-before: step-5
|
||||
|
||||
.. only:: libcloud
|
||||
|
||||
.. literalinclude:: ../samples/libcloud/durability.py
|
||||
@ -217,6 +240,39 @@ the same:
|
||||
|
||||
7513986d3aeb22659079d1bf3dc2468b
|
||||
|
||||
.. only:: jclouds
|
||||
|
||||
.. literalinclude:: ../samples/jclouds/Durability.java
|
||||
:language: java
|
||||
:start-after: step-5
|
||||
:end-before: step-6
|
||||
|
||||
::
|
||||
|
||||
Objects in fractals:
|
||||
SwiftObject{name=an amazing goat,
|
||||
uri=https://swift.some.org:8888/v1/AUTH_8997868/fractals/an%20amazing%20goat,
|
||||
etag=439884df9c1c15c59d2cf43008180048,
|
||||
lastModified=Wed Nov 25 15:09:34 AEDT 2015, metadata={}}
|
||||
|
||||
.. literalinclude:: ../samples/jclouds/Durability.java
|
||||
:language: java
|
||||
:start-after: step-6
|
||||
:end-before: step-7
|
||||
|
||||
::
|
||||
|
||||
Fetched: an amazing goat
|
||||
|
||||
.. literalinclude:: ../samples/jclouds/Durability.java
|
||||
:language: java
|
||||
:start-after: step-7
|
||||
:end-before: step-8
|
||||
|
||||
::
|
||||
|
||||
MD5 for file goat.jpg: 439884df9c1c15c59d2cf43008180048
|
||||
|
||||
|
||||
.. only:: libcloud
|
||||
|
||||
@ -254,6 +310,13 @@ Finally, clean up by deleting the test object:
|
||||
:start-after: step-8
|
||||
:end-before: step-9
|
||||
|
||||
.. only:: jclouds
|
||||
|
||||
.. literalinclude:: ../samples/jclouds/Durability.java
|
||||
:language: java
|
||||
:start-after: step-8
|
||||
:end-before: step-10
|
||||
|
||||
.. only:: libcloud
|
||||
|
||||
.. literalinclude:: ../samples/libcloud/durability.py
|
||||
@ -278,7 +341,7 @@ Back up the Fractals from the database on the Object Storage
|
||||
Back up the Fractals app images, which are currently stored inside the
|
||||
database, on Object Storage.
|
||||
|
||||
Place the images in the :code:`fractals`' container:
|
||||
Place the images in the :code:`fractals` container:
|
||||
|
||||
.. only:: fog
|
||||
|
||||
@ -286,6 +349,13 @@ Place the images in the :code:`fractals`' container:
|
||||
:start-after: step-10
|
||||
:end-before: step-11
|
||||
|
||||
.. only:: jclouds
|
||||
|
||||
.. literalinclude:: ../samples/jclouds/Durability.java
|
||||
:language: java
|
||||
:start-after: step-10
|
||||
:end-before: step-11
|
||||
|
||||
.. only:: libcloud
|
||||
|
||||
.. literalinclude:: ../samples/libcloud/durability.py
|
||||
@ -293,7 +363,7 @@ Place the images in the :code:`fractals`' container:
|
||||
:end-before: step-11
|
||||
|
||||
Next, back up all existing fractals from the database to the swift container.
|
||||
A simple `for` loop takes care of that:
|
||||
A simple loop takes care of that:
|
||||
|
||||
.. note:: Replace :code:`IP_API_1` with the IP address of the API instance.
|
||||
|
||||
@ -303,6 +373,13 @@ A simple `for` loop takes care of that:
|
||||
:start-after: step-11
|
||||
:end-before: step-12
|
||||
|
||||
.. only:: jclouds
|
||||
|
||||
.. literalinclude:: ../samples/jclouds/Durability.java
|
||||
:language: java
|
||||
:start-after: step-11
|
||||
:end-before: step-12
|
||||
|
||||
.. only:: libcloud
|
||||
|
||||
.. literalinclude:: ../samples/libcloud/durability.py
|
||||
@ -336,8 +413,8 @@ Extra features
|
||||
Delete containers
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
To delete a container, make sure that you have removed all objects from the
|
||||
container before running this script. Otherwise, the script fails:
|
||||
To delete a container, you must first remove all objects from the container.
|
||||
Otherwise, the delete operation fails:
|
||||
|
||||
.. only:: fog
|
||||
|
||||
@ -345,6 +422,13 @@ container before running this script. Otherwise, the script fails:
|
||||
:start-after: step-12
|
||||
:end-before: step-13
|
||||
|
||||
.. only:: jclouds
|
||||
|
||||
.. literalinclude:: ../samples/jclouds/Durability.java
|
||||
:language: java
|
||||
:start-after: step-12
|
||||
:end-before: step-13
|
||||
|
||||
.. only:: libcloud
|
||||
|
||||
.. literalinclude:: ../samples/libcloud/durability.py
|
||||
@ -358,19 +442,33 @@ Add metadata to objects
|
||||
|
||||
You can complete advanced tasks such as uploading an object with metadata, as
|
||||
shown in following example. For more information, see the documentation for
|
||||
your SDK. This option also uses a bit stream to upload the file, iterating bit
|
||||
by bit over the file and passing those bits to Object Storage as they come.
|
||||
Compared to loading the entire file in memory and then sending it, this method
|
||||
is more efficient, especially for larger files.
|
||||
your SDK.
|
||||
|
||||
.. only:: fog
|
||||
|
||||
This option also uses a bit stream to upload the file, iterating bit
|
||||
by bit over the file and passing those bits to Object Storage as they come.
|
||||
Compared to loading the entire file in memory and then sending it, this method
|
||||
is more efficient, especially for larger files.
|
||||
|
||||
.. literalinclude:: ../samples/fog/durability.rb
|
||||
:start-after: step-13
|
||||
:end-before: step-14
|
||||
|
||||
.. only:: jclouds
|
||||
|
||||
.. literalinclude:: ../samples/jclouds/Durability.java
|
||||
:language: java
|
||||
:start-after: step-13
|
||||
:end-before: step-14
|
||||
|
||||
.. only:: libcloud
|
||||
|
||||
This option also uses a bit stream to upload the file, iterating bit
|
||||
by bit over the file and passing those bits to Object Storage as they come.
|
||||
Compared to loading the entire file in memory and then sending it, this method
|
||||
is more efficient, especially for larger files.
|
||||
|
||||
.. literalinclude:: ../samples/libcloud/durability.py
|
||||
:start-after: step-13
|
||||
:end-before: step-14
|
||||
@ -389,6 +487,20 @@ For efficiency, most Object Storage installations treat large objects,
|
||||
:start-after: step-14
|
||||
:end-before: step-15
|
||||
|
||||
.. only:: jclouds
|
||||
|
||||
If you work with large objects, use the :code:`RegionScopedBlobStoreContext`
|
||||
class family instead of the ones used so far.
|
||||
|
||||
.. note:: Large file uploads that use the :code:`openstack-swift` provider
|
||||
are supported in only jclouds V2, currently in beta. Also, the
|
||||
default chunk size is 64 Mb. Consider changing this as homework.
|
||||
|
||||
.. literalinclude:: ../samples/jclouds/Durability.java
|
||||
:language: java
|
||||
:start-after: step-14
|
||||
:end-before: step-15
|
||||
|
||||
.. only:: libcloud
|
||||
|
||||
If you work with large objects, use the :code:`ex_multipart_upload_object`
|
||||
@ -401,6 +513,19 @@ For efficiency, most Object Storage installations treat large objects,
|
||||
:start-after: step-14
|
||||
:end-before: step-15
|
||||
|
||||
.. only:: jclouds
|
||||
|
||||
Complete code sample
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This file contains all the code from this tutorial section. This
|
||||
class lets you view and run the code.
|
||||
|
||||
Before you run this class, confirm that you have configured it for
|
||||
your cloud and the instance running the Fractals application.
|
||||
|
||||
.. literalinclude:: ../samples/jclouds/Durability.java
|
||||
:language: java
|
||||
|
||||
Next steps
|
||||
----------
|
||||
|
Loading…
Reference in New Issue
Block a user