Quickstart for Cloud Block Storage#

Cloud Block Storage provides dependable performance for your I/O-intensive applications by providing a block level storage solution that allows you to mount drives or volumes to your Next Generation Cloud Servers. The two primary use cases are (1) to allow you to scale your storage independently from your compute resources and (2) to allow you to utilize high performance storage to serve database or I/O-intensive applications.

You have your choice of SSD or SATA volume types:

SATA

SATA volumes work well for your everyday file system needs. This is the default volume type.

SSD

SSD volumes deliver even higher performance for databases and other I/O-intensive applications.

Plus, you don’t have to scale up your servers; both standard and SSD volumes work with all sizes of next-generation Cloud Servers.

Concepts#

To use this service effectively, you should understand how these key ideas are used in this context:

Snapshot

A point-in-time copy of the data that a volume contains. Snapshots are incremental, so each time that you create a snapshot, the incremental changes for the new snapshot are appended to the previous snapshot, which is still available.

Volume

A detachable block storage device. You can think of it as a USB hard drive. You can attach a volume to one instance at a time.

Authentication#

To use this service you have to authenticate first. To do this, you will need your Rackspace username and API key. Your username is the one you use to login to the Cloud Control Panel at http://mycloud.rackspace.com/.

To find your API key, use the instructions in View and reset your API key.

You can specify a default region. Here is a list of available regions:

  • DFW (Dallas-Fort Worth, TX, US)

  • HKG (Hong Kong, China)

  • IAD (Blacksburg, VA, US)

  • LON (London, England)

  • SYD (Sydney, Australia)

Some users have access to another region in ORD (Chicago, IL). New users will not have this region.

Once you have these pieces of information, you can pass them into the SDK by replacing {username}, {apiKey}, and {region} with your info:

CloudIdentity cloudIdentity = new CloudIdentity()
{
    APIKey = "{apiKey}",
    Username = "{username}"
};
CloudIdentityProvider cloudIdentityProvider = new CloudIdentityProvider(cloudIdentity);
UserAccess userAccess = cloudIdentityProvider.Authenticate(cloudIdentity);
import (
  "github.com/rackspace/gophercloud"
  "github.com/rackspace/gophercloud/rackspace"
  "github.com/rackspace/gophercloud/rackspace/blockstorage/v1/snapshots"
  "github.com/rackspace/gophercloud/rackspace/blockstorage/v1/volumes"

  osvolumes "github.com/rackspace/gophercloud/openstack/blockstorage/v1/volumes"
)

ao := gophercloud.AuthOptions{
  Username: "{username}",
  APIKey: "{apiKey}",
}
provider, err := rackspace.AuthenticatedClient(ao)

serviceClient, err := rackspace.NewBlockStorageV1(provider, gophercloud.EndpointOpts{
  Region: "{region}",
})
// Authentication in jclouds is lazy and happens on the first call to the cloud.
CinderApi cinderApi = ContextBuilder.newBuilder("rackspace-cloudblockstorage-us")
    .credentials("{username}", "{apiKey}")
    .buildApi(CinderApi.class);
pkgcloud = require('pkgcloud');

// each client is bound to a specific service and provider
var client = pkgcloud.blockstorage.createClient({
  provider: 'rackspace',
  username: '{username}',
  apiKey: '{apiKey}',
  region: '{region}'
});
require 'vendor/autoload.php';

use OpenCloud\Rackspace;

// Instantiate a Rackspace client.
$client = new Rackspace(Rackspace::US_IDENTITY_ENDPOINT, array(
    'username' => '{username}',
    'apiKey'   => '{apiKey}'
));

$volumeService = $client->volumeService();
import pyrax
pyrax.set_credentials("{username}", "{apiKey}", region="{region}")
cbs = pyrax.cloud_blockstorage
require 'fog'

@client = Fog::Rackspace::BlockStorage.new(
  :rackspace_username => '{username}',
  :rackspace_api_key => '{apiKey}',
  :rackspace_region => '{region}'
)
# {username}, {apiKey} below are placeholders, do not enclose '{}' when you replace them with actual credentials.

$ curl -s https://identity.api.rackspacecloud.com/v2.0/tokens -X 'POST' \
  -d '{"auth":{"RAX-KSKEY:apiKeyCredentials":{"username":"{username}", "apiKey":"{apiKey}"}}}' \
  -H "Content-Type: application/json" | python -m json.tool

# From the resulting json, set three environment variables: tenant, TOKEN and endpoint

export TENANT="{tenantId}"
export TOKEN="{tokenId}"
export ENDPOINT="{publicUrl}" # For Block Storage service

Use the API#

Some of the basic operations you can perform with this API are described below.

Volume operations#

You can perform create, read, update, and delete operations on volumes.

Create volume#

To create a block storage volume in its basic form:

new CloudBlockStorageProvider({cloudIdentity}).CreateVolume(
     size: {size},
     displayDescription: "{description}",
     displayName: "{name}",
     region: "{region}");
opts := osvolumes.CreateOpts{
  Name: "photos",
  Size: 100,
}
vol, err := volumes.Create(serviceClient, opts).Extract()
VolumeApi volumeApi = cinderApi.getVolumeApi("{region}");

CreateVolumeOptions options = CreateVolumeOptions.Builder
        .name("photos")
        .volumeType("SATA");

Volume volume = volumeApi.create(100, options);
// To create the volume, specify a name and size (in GB, with a miminum of
// 100GB). You may optionally specify a volume type, which is either 'SSD'
// (faster, more expensive), or 'SATA' (more affordable). SATA is the
// default if you omit this.

client.createVolume({
  name: 'photos',
  volumeType: 'SATA',
  size: 100
}, function(err, volume) {
  if (err) {
    // TODO handle as appropriate
  }

  // TODO use your newly created volume
});
// To create the volume, specify a name and size (in GB, with a miminum of
// 100GB). You may optionally specify a volume type, which is either 'SSD'
// (faster, more expensive), or 'SATA' (more affordable). SATA is the
// default if you omit this.

$volume = $volumeService->volume();
$volume->create(array(
    'display_name' => 'photos',
    'size' => 100,
    'volume_type' => 'SATA'
));
# To create the volume, specify a name and size (in GB, minimum 100GB). You
# may optionally specify a volume type, which is either 'SSD' (faster, more
# expensive), or 'SATA' (more affordable). SATA is the default if you omit
# this.

vol = cbs.create('photos', 100, 'SATA')
# The :size parameter is specified in GB, with a minimum of 100GB.
# The :volume_type parameter may be either 'SSD' (faster, more expensive), or
# 'SATA' (more affordable). SATA is the default it you omit this.
volume = @client.volumes.create(
  :display_name => 'photos',
  :size => '100',
  :volume_type => 'SATA'
)
volume.wait_for { ready? }
$ curl -X POST -d \
  '{
  "volume": {
      "display_name": "{name}",
      "size": 100
   }
  }'\
  -H "X-Auth-Token: $TOKEN" \
  -H "Content-Type: application/json" \
  $ENDPOINT/volumes | python -m json.tool

List volumes#

To see a list of all the block storage volumes you have created in a single region:

IEnumerable<Volume> volumeList = cbsProvider.ListVolumes(region: "{region}");
err := volumes.List(serviceClient).EachPage(func(page pagination.Page) (bool, error) {
  volumeList, err := volumes.ExtractVolumes(page)
  for _, v := range volumeList {
    // ...
  }
  return true, nil
})
VolumeApi volumeApi = cinderApi.getVolumeApi("{region}");

List<Volume> volumes = volumeApi.listInDetail().toList();
client.getVolumes(function(err, volumes) {
  if (err) {
    // TODO handle as appropriate
  }

  // TODO use your list of volumes
});
$volumes = $volumeService->volumeList();
volumes = cbs.list()
volumes = @client.volumes.all
curl -X GET $ENDPOINT/volumes \
  -H "X-Auth-Token: $TOKEN" \
  -H "Content-Type: application/json" | python -m json.tool

Show volume#

To inspect a specific volume’s state:

Volume volume =
      new CloudBlockStorageProvider({cloudIdentity}).ShowVolume("{volumeId}", region: "{region}");
v, err := volumes.Get(serviceClient, "{volumeId}").Extract()
VolumeApi volumeApi = cinderApi.getVolumeApi("{region}");

Volume volume = volumeApi.get("{volumeId}");
client.getVolume('{volumeId}', function(err, volume) {
  if (err) {
    // TODO handle as appropriate
  }

  // TODO use the retrieved volume
});
$volume = $volumeService->volume('{volumeId}');
volume = cbs.get('{volumeId}')
volume = @client.volumes.get('{volumeId}')
$ curl -X GET $ENDPOINT/volumes/{volumeId}
  -H "X-Auth-Token: $TOKEN" \
  -H "Content-Type: application/json" | python -m json.tool

Update volume#

To modify a volume’s display name and/or description:

// Not currently supported by this SDK
opts := volumes.UpdateOpts{Name: "new_name"}
v, err := volumes.Update{serviceClient, "{volumeId}", opts).Extract()
// Not currently supported by this SDK
// assuming we've already loaded the details of a volume into a
// local variable named volume

volume.name = 'New Volume Name';

client.updateVolume(volume, function(err) {
  if (err) {
    // TODO handle as appropriate
  }
});
$volume->rename(array(
    'display_name' => 'New Volume Name'
));
vol.update(display_name='New Volume Name')
# Not currently supported by this SDK
curl -X PUT $ENDPOINT/volumes/{volumeId} \
  -H "X-Auth-Token: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "snapshot": {
      "display_name": "New Volume Name"
    }
  }' | python -m json.tool

Delete volume#

To delete a volume when it is no longer in use (attached) and the data it contains is not needed:

new CloudBlockStorageProvider({cloudIdentity}).DeleteVolume("{volumeId}", "{region}");
err := volumes.Delete(serviceClient, "{volumeId}").ExtractErr()
VolumeApi volumeApi = cinderApi.getVolumeApi("{region}");

volumeApi.delete("{volumeId}");
client.deleteVolume(volumeId, function(err) {
  if (err) {
    // TODO handle as appropriate
  }
});
$volume->delete();
vol.delete()
# Or:
# cbs.delete(vol)
volume.destroy
$ curl -X DELETE $ENDPOINT/volumes/{volumeId} \
  -H "X-Auth-Token: $TOKEN" \
  -H "Content-Type: application/json" | python -m json.tool

Note: please be advised that deleting a volume deletes all the data within it and cannot be recovered unless such data was previously backed up.

Snapshot operations#

You can perform create, read, update, and delete operations on snapshots.

Create snapshot#

To create a snapshot of a block storage volume:

new CloudBlockStorageProvider({cloudIdentity}).CreateSnapshot(
      "{volumeId}",
      displayName: "{name}",
      displayDescription: "{description}",
      region: "{region}");
opts := snapshots.CreateOpts{VolumeID: "{volumeId}", Name: "{snapshotName}"}
s, err := snapshots.Create(serviceClient, opts).Extract()
VolumeApi volumeApi = cinderApi.getVolumeApi("{region}");
SnapshotApi snapshotApi = cinderApi.getSnapshotApi("{region}");

// Get the volume to snapshot
Volume volume = volumeApi.get("{volumeId}")

CreateSnapshotOptions options = CreateSnapshotOptions.Builder
    .name("{name}")
    .description("This is the description");

Snapshot snapshot = snapshotApi.create("{volumeId}", options);
// To create a snapshot for a volume, the volume should be detached from
// any server. You must supply a name for the snapshot, and may provide
// an optional description.

client.createSnapshot({
  name: 'name-here',
  description: 'This is the description',
  volumeId: '{volumeId}'
}, function(err, snapshot) {
  if (err) {
    // TODO handle as appropriate
  }

  // TODO use your newly created snapshot
});
// To create a snapshot for a volume, the volume should be detached from
// any server. You must supply a name for the snapshot, and may provide
// an optional description.

$snapshot = $volumeService->snapshot();
$snapshot->create(array(
    'display_name' => 'name-here',
    'display_description' => 'This is the description',
    'volume_id' => $volume->id()
));
# To create a snapshot for a volume, the volume should be detached from
# any server. You must supply a name for the snapshot, and may provide
# an optional description.

snap = vol.create_snapshot('name-here', 'This is the description')
# To create a snapshot for a volume, the volume should be detached from
# any server. You must supply a name for the snapshot, and may provide
# an optional description.

snapshot = volume.create_snapshot(
  :display_name => 'name-here',
  :display_description => 'This is the description'
)
$ curl -X POST -d \
  '{
  "snapshot": {
      "display_name": "{name}",
      "display_description": "{description}",
      "volume_id": "{volumeId}"
    }
  }'\
  -H "X-Auth-Token: $TOKEN" \
  -H "Content-Type: application/json" \
  $ENDPOINT/snapshots | python -m json.tool

List snapshots#

To see all the snapshots you have created in a given region:

IEnumerable<Snapshot> snapshots = cbsProvider.ListSnapshots(region: "{region}");
err := snapshots.List(serviceClient).EachPage(func(page pagination.Page) (bool, error) {
  snapshotList, err := snapshots.ExtractSnapshots(page)
  for _, s := range snapshotList {
    // ...
  }
  return true, nil
})
SnapshotApi snapshotApi = cinderApi.getSnapshotApi("{region}");

List<Snapshot> snapshots = snapshotApi.listInDetail().toList();
client.getSnapshots(function(err, snapshots) {
  if (err) {
    // TODO handle as appropriate
  }

  // TODO use your list of snapshots
});
$snapshots = $volumeService->snapshotList(array(
  'volume_id' => $volume->id()
));
snapshots = vol.list_snapshots()
snapshots = @client.snapshots.all

# To fetch only snapshots associated with a given volume:
volume.snapshots
curl -X GET $ENDPOINT/snapshots \
  -H "X-Auth-Token: $TOKEN" \
  -H "Content-Type: application/json" | python -m json.tool

Show snapshot details#

To inspect detailed metadata of a specific snapshot:

Snapshot snapshot =
      new CloudBlockStorageProvider({cloudIdentity}).ShowSnapshot("{snapshotId}", "{region}");
s, err := snapshots.Get(serviceClient, "{snapshotId}").Extract()
SnapshotApi snapshotApi = cinderApi.getSnapshotApi("{region}");

Snapshot snapshot = snapshotApi.get("{snapshotId}");
client.getShapshot('{snapshotId}', function(err, snapshot) {
  if (err) {
    // TODO handle as appropriate
  }

  // TODO use the retrieved snapshot
});
$snapshot = $volumeService->snapshot('{snapshotId}');
snapshot = cbs.get_snapshot('{snapshotId}')
snapshot @client.snapshots.get('{snapshotId}')
$ curl -X GET $ENDPOINT/snapshots/{snapshotId}
  -H "X-Auth-Token: $TOKEN" \
  -H "Content-Type: application/json" | python -m json.tool

Update snapshot#

To modify a snapshot’s display name and/or description:

// Not currently supported by this SDK
// Only Name and Description may be updated
opts := snapshots.UpdateOpts{Name: "new_name"}
s, err := snapshots.Update(serviceClient, "{snapshotId}", opts).Extract()
// Not currently supported by this SDK
      // assuming we've already loaded the details of a snapshot into a
      // local variable named snapshot

snapshot.name = 'New Snapshot Name';

client.updateSnapshot(snapshot, function(err) {
  if (err) {
    // TODO handle as appropriate
  }
});
$snapshot->rename(array(
  'display_name' => 'new_snapshot_name'
));
snapshot.update(display_name='New Snapshot Name')
# Not currently supported by this SDK
curl -X PUT $ENDPOINT/snapshots/{snapshotId} \
  -H "X-Auth-Token: $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "snapshot": {
      "display_name": "New Snapshot Name"
    }
  }' | python -m json.tool

Delete snapshot#

To permanently delete a snapshot:

new CloudBlockStorageProvider({cloudIdentity}).DeleteSnapshot("{snapshotId}", "{region}");
err := snapshots.Delete(serviceClient, "{snapshotId}").ExtractErr()
SnapshotApi snapshotApi = cinderApi.getSnapshotApi("{region}");

snapshotApi.delete("{snapshotId}");
client.deleteSnapshot(snapshotId, function(err) {
  if (err) {
    // TODO handle as appropriate
  }
});
$snapshot->delete();
snap.delete()
# Or:
# cbs.delete_snapshot('{snapId}')
snapshot.destroy
$ curl -X DELETE $ENDPOINT/snapshots/{snapshotId} \
  -H "X-Auth-Token: $TOKEN" \
  -H "Content-Type: application/json" | python -m json.tool

More information#

This quickstart is intentionally brief, demonstrating only a few basic operations. To learn more about interacting with Rackspace cloud services, explore the following sites: