Quickstart for Cloud Servers#

Rackspace Cloud Servers allows you to allocate and deallocate compute resources. It is based on OpenStack Compute (Nova), a community-led open-source platform.

Concepts#

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

server

A computer that provides explicit services to the client software running on that system. A server is a virtual machine (VM) instance in the Cloud Servers environment. To create a server, you must specify a name, flavor reference, and image reference.

image

The type of operating system you want to use. You can choose from pre-defined images or create your own custom images.

flavor

A resource configuration for a server. Each flavor is a unique combination of disk, memory, vCPUs, and network bandwidth. You can choose from pre-defined flavors.

network

The virtual space where your servers live. Rackspace has two default networks: PublicNet, which is the Internet; ServiceNet, which is our internal network. Although you can create as many isolated networks as you want, the default configuration is for servers to be connected to both PublicNet (for public Internet connectivity) and ServiceNet (for internal connectivity with your other servers).

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}"
};
CloudServersProvider cloudServersProvider = new CloudServersProvider(cloudIdentity);
import (
  "github.com/rackspace/gophercloud"
  "github.com/rackspace/gophercloud/rackspace"
  "github.com/rackspace/gophercloud/rackspace/compute/v2/images"
  "github.com/rackspace/gophercloud/rackspace/compute/v2/flavors"
  "github.com/rackspace/gophercloud/rackspace/compute/v2/servers"
  "github.com/rackspace/gophercloud/rackspace/compute/v2/keypairs"

  oskeypairs "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs"
)

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

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

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

use OpenCloud\Rackspace;

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

$service = $client->computeService(null, '{region}');
import pyrax

pyrax.set_setting("identity_type", "rackspace")
pyrax.set_default_region('{region}')
pyrax.set_credentials('{username}', '{apiKey}')

cs = pyrax.cloudservers
require 'fog'

@client = Fog::Compute.new(
  :provider => 'rackspace',
  :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 the compute service

Use the API#

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

Set up your first server#

Once you’ve finished your initial setup, you can begin the process of creating your first server.

To do this, you need to decide which Image and Flavor you want to use.

Choose operating system#

An image, or operating system, forms the basis of your server. Each image has a unique ID, which is used to retrieve more details from the API. If you already know the ID, you can retrieve more details about the image:

ServerImage serverImage = cloudServersProvider.GetImage("{image_id}");
image, err := images.Get(serviceClient, "{imageId}").Extract()
ImageApi imageApi = novaApi.getImageApi("{region}");

Image image = imageApi.get("{imageId}");
client.getImage(imageId, function(err, image) {
  if (err) {
    // TODO handle as appropriate
    return;
  }

  // TODO use your image here
});
$image = $service->image('{imageId}');
image = pyrax.images.get('{imageId}')
image = @client.images.get('{imageId}')
curl -X GET $ENDPOINT/images/{imageId} \
  -H "X-Auth-Token: $TOKEN" | python -m json.tool

Alternatively, you can traverse through the list of images:

IEnumerable<SimpleServerImage> imageList = cloudServersProvider.ListImages();
err := images.List(serviceClient).EachPage(func (page pagination.Page) (bool, error) {
  images, err := images.ExtractImages(page)
  // Use the page of []images.Image
  return true, nil
}
ImageApi imageApi = novaApi.getImageApi("{region}");

ImmutableList<? extends Image> images = imageApi.listInDetail().concat().toList();
client.getImages(function(err, images) {
  if (err) {
    // TODO handle as appropriate
    return;
  }

  // TODO decide on an image to use
});
$images = $service->imageList();
images = pyrax.images.list()
@client.images.all
curl -X GET $ENDPOINT/images \
  -H "X-Auth-Token: $TOKEN" | python -m json.tool

# Choose an image from the list and note its id.
export IMAGE_ID="{imageId}"

Once you’ve found the appropriate operating system and its ID, you can move on to picking your hardware.

Choose hardware configuration#

Flavors, or hardware configurations, dictate how powerful your servers are. Like images, each flavor has its own UUID. If you already know which flavor to use, you can retrieve its details:

FlavorDetails flavorDetails = cloudServersProvider.GetFlavor("{flavor_id}");
flavor, err := flavors.Get(serviceClient, "{flavorId}").Extract()
FlavorApi flavorApi = novaApi.getFlavorApi("{region}");

Flavor flavor = flavorApi.get("{flavorId}");
client.getFlavor(flavorId, function(err, flavor) {
  if (err) {
    // TODO handle as appropriate
    return;
  }

  // TODO use your flavor here
});
$flavor = $service->flavor('{flavorId}');
flavor = cs.flavors.get('{flavorId}')
flavor = @client.flavor.get('{flavorId}')
curl -X GET $ENDPOINT/flavors/{flavorId} \
      -H "X-Auth-Token: $TOKEN" | python -m json.tool

Alternatively, you can traverse through the standard list Rackspace provides:

IEnumerable<Flavor> flavorList = cloudServersProvider.ListFlavors();
err := flavors.List(serviceClient).EachPage(func (page pagination.Page) (bool, error) {
  flavors, err := flavors.ExtractFlavors(page)
  // Use the page of []flavors.Flavor
  return true, nil
}
FlavorApi flavorApi = novaApi.getFlavorApi("{region}");

ImmutableList<? extends Flavor> flavors = flavorApi.listInDetail().concat().toList();
client.getFlavors(function(err, flavors) {
  if (err) {
    // TODO handle as appropriate
    return;
  }

  // TODO figure out which flavors to use
  // just grab the first flavor id
  var flavorId = flavors[0].id;
});
$flavors = $service->flavorList();
flavor_list = cs.list_flavors()
@client.flavors.all
curl -X GET $ENDPOINT/flavors \
  -H "X-Auth-Token: $TOKEN" | python -m json.tool

# Choose a flavor from the list and note its id.
export FLAVOR_ID="{flavorId}"

Build server#

Now that you have an image ID and flavor ID, you can create your server:

NewServer newServer = cloudServersProvider.CreateServer("{server_name}", "{image_id}", "{flavor_id}");
server, err := servers.Create(serviceClient, servers.CreateOpts{
  Name:      "My new server",
  ImageRef:  image.ID,
  FlavorRef: flavor.ID,
}).Extract()
ServerApi serverApi = novaApi.getServerApi("{region}");

ServerCreated serverCreated = serverApi.create("My new server", "{imageId}", "{flavorId}");
client.createServer({
  name: 'My new server',
  image: imageId,
  flavor: flavorId
}, function(err, server) {
  if (err) {
    // TODO handle as appropriate
    return;
  }

  // TODO use your server here
});
$server = $service->server();

$response = $server->create(array(
    'name'     => 'My new server',
    'imageId'  => $image->getId(),
    'flavorId' => $flavor->getId()
));
server = cs.servers.create('bessie01', image.id, flavor.id)
server = @client.servers.create(
  :name => 'My new server',
  :image_id => image.id,
  :flavor_id => flavor.id
)
# Reminder: all {variableNames} are placeholders only. Must be replaced by actual and valid values
curl -X POST $ENDPOINT/servers -d \
  '{
    "server" : {
        "name" : "My new server",
        "imageRef": "'"$IMAGE_ID"'",
        "flavorRef": '"$FLAVOR_ID"',
      }
    }' \
    -H "Content-Type: application/json" \
    -H "X-Auth-Token: $TOKEN" | python -m json.tool

export SERVER_ID="{serverId}"

This is an asynchronous operation, meaning that it will _not_ block your request while the build process runs. It will provision your VM behind the scenes. When the build completes, it places your server in an ACTIVE state. At this point, the server is available for you to use.

Some SDKs allow you to check on the status of the build:

Server server = cloudServersProvider.WaitForServerActive(newServer.Id);
err := servers.WaitForStatus(serviceClient, server.ID, "ACTIVE", 600)
ServerApi serverApi = novaApi.getServerApi("{region}");

ServerPredicates.awaitActive(serverApi).apply("{serverId}")
server.setWait({ status: server.STATUS.running }, 6000, function(err) {
  if (err) {
    // TODO handle err as appropriate
  }

  // TODO continue after status is running
});
$server->waitFor('ACTIVE', 600);
pyrax.utils.wait_for_build(server, verbose=True)
server.wait_for { active }
# from resulting json below see "status"
curl -X GET $ENDPOINT/servers/$SERVER_ID \
  -H "X-Auth-Token: $TOKEN" | python -m json.tool

Delete server#

To permanently delete a server:

cloudServersProvider.DeleteServer("{server_id}");
err := servers.Delete(serviceClient, server.ID)
ServerApi serverApi = novaApi.getServerApi("{region}");

serverApi.delete("{serverId}");
client.destroyServer(server, function(err) {
  // TODO handle err as appropriate
});
$server->delete();
server.delete()
server.destroy
curl -X DELETE $ENDPOINT/servers/$SERVER_ID -H "X-Auth-Token: $TOKEN"

Manage keypairs#

By default, servers use password-based authentication. When a server is created, the HTTP response contains a root password that is required for all subsequent SSH connections. You do have the option, however, of using keypairs instead.

Register keypair#

To use keypair-based authentication, the API needs to know about it. You have two options: upload your existing key, or have the API create a new one for you. We’ll cover both.

Upload keypair:

// This is not supported through the .NET SDK at this time
pubkey, err := ioutil.ReadFile("/home/my-user/.ssh/id_rsa.pub")
kp, err := keypairs.Create(serviceClient, oskeypairs.CreateOpts{
  Name: "my-keypair",
  PublicKey: string(pubkey),
}).Extract()
KeyPairApi keyPairApi = novaApi.getKeyPairApi("{region}").get();

File keyPairFile = new File("{/home/my-user/.ssh/id_rsa.pub}");
String publicKey = Files.toString(keyPairFile, UTF_8); // Using com.google.common.io.Files

KeyPair keyPair = keyPairApi.createWithPublicKey("my-keypair", publicKey);
// we need the fs module to access the local disk
var fs = require('fs');

// TODO provide the path to your existing key.
var keyPath = '/home/my-user/.ssh/id_rsa.pub';

fs.readFile(keyPath, function(err, data) {
  client.addKey({
    name: 'my-keypair',
    'public_key': data.toString()
  }, function (err, key) {
    if (err) {
      // TODO handle as appropriate
      return;
    }

    // TODO use your key
  });
});
$keypair = $service->keypair();

$keypair->create(array(
   'name'      => 'my-keypair',
   'publicKey' => file_get_contents('/home/my-user/.ssh/id_rsa.pub')
));
import os

public_key = open(os.path.expanduser("~/.ssh/id_rsa.pub")).read()
keypair = cs.keypairs.create("mykeypair", public_key)
key_pair = @client.key_pairs.create(
  :name => 'my-keypair',
  :public_key => File.read('/home/my-user/.ssh/id_rsa.pub')
)
curl -X POST $ENDPOINT/os-keypairs -d \
  '{
  "keypair":{
      "name":"{keyPairName}",
      "public_key":"ssh-rsa AAAAB3Nz ..."
    }
  }' \
  -H "Content-Type: application/json" \
  -H "X-Auth-Token: $TOKEN" | python -m json.tool

or have the API create one:

// This is not supported through the .NET SDK at this time
kp, err := keypairs.Create(serviceClient, oskeypairs.CreateOpts{
  Name: "my-keypair",
}).Extract()
KeyPairApi keyPairApi = novaApi.getKeyPairApi("{region}").get();

KeyPair keyPair = keyPairApi.create("my-keypair");

File keyPairFile = new File("my-keypair.pem");
// Using com.google.common.io.Files
Files.write(keyPair.getPrivateKey(), keyPairFile, UTF_8);
client.addKey({ name: 'my-keypair' }, function (err, key) {
  if (err) {
    // TODO handle as appropriate
    return;
  }

  // TODO use your key
});
// Get the API to generate a new keypair.
$keypair = $service->keypair();
$keypair->create(array(
   'name' => 'my-keypair'
));

// Save the generated key to your local filesystem and set appropriate permissions.
$localPath = 'my-keypair.pem';
file_put_contents($localPath, $keypair->getPrivateKey());
chmod($localPath, 0600);
# Not currently supported by this SDK
key_pair = @client.key_pairs.create(:name => 'my-keypair')
File.write('my-keypair.pem', key_pair.private_key, :perm => 0600)
curl -X POST $ENDPOINT/os-keypairs -d \
  '{"keypair":{"name":"{keyPairName}"} }' \
  -H "Content-Type: application/json" \
  -H "X-Auth-Token: $TOKEN" | python -m json.tool

Use keypairs#

If you want an existing server to use keypair-based auth, you will need to configure this yourself.

However, getting new servers to acknowledge keypairs is easy. You just need to supply the name of the pre-existing keypair when you do the create server operation, like this:

// This is not supported through the .NET SDK at this time
server, err := servers.Create(serviceClient, servers.CreateOpts{
  Name:      "My server",
  ImageRef:  image.ID,
  FlavorRef: flavor.ID,
  KeyPair:   "my-keypair",
}).Extract()
ServerApi serverApi = novaApi.getServerApi("{region}");

CreateServerOptions options = CreateServerOptions.Builder.keyPairName("my-keypair");
ServerCreated serverCreated = serverApi.create("My server", "{imageId}", "{flavorId}", options);
client.createServer({
  name: 'My server',
  image: imageId,
  flavor: flavorId,
  keyname: 'my-keypair'
}, function(err, server) {
  if (err) {
    // TODO handle as appropriate
    return;
  }

  // TODO use your server here
});
$server = $service->server();

$response = $server->create(array(
    'name'     => 'My server',
    'imageId'  => $image->getId(),
    'flavorId' => $flavor->getId(),
    'keypair'  => 'my-keypair'
));
server = cs.servers.create('My server', image.id, flavor.id,
                           key_name=keypair.name)
server = @client.servers.create(
  :name => 'My server',
  :image_id => image.id,
  :flavor_id => flavor.id,
  :key_name => 'my-keypair'
)
curl -X POST $ENDPOINT/servers -d \
  '{
    "server" : {
      "name" : "My server",
      "imageRef": "'"$IMAGE_ID"'",
      "flavorRef": '"$FLAVOR_ID"',
      "key_name" : "my-keypair"
    }
  }' \
  -H "Content-Type: application/json" \
  -H "X-Auth-Token: $TOKEN" | python -m json.tool

This server, after being spun up, will respond to that keypair.

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: