Getting Started With The OpenStack NET SDK

unknown edited this page Aug 27, 2013 · 8 revisions

Getting Started with the OpenStack SDK for Microsoft .NET

About this document

This document will describe the steps required (including sample code) to allow a .NET developer to use the OpenStack .NET Software Development Kit (SDK). It assumes no prior knowledge of OpenStack and a very basic understanding of Cloud Computing in general.

This document has the following sections:

  • Requirements
  • Credentials
  • Installing The SDK
  • Getting A Server Up And Running
  • Creating And Using A Server Image
  • Storing Files In The Cloud
  • Creating A Content Delivery Network (CDN)
  • Creating A Network Of Servers

Requirements

Microsoft .NET Framework 4.0.

The SDK has also seen limited used with Mono.

Credentials

To obtain credentials for the US Rackspace Cloud, please sign up for an account at US Rackspace Open Cloud. Once an account is created, you can login to the Cloud Control Panel (US), find your credentials by clicking on your username in the top right corner, and then select API keys.

Likewise, you can create an account on our UK Rackspace Open Cloud by signing up at UK Rackspace Open Cloud and then logging into Cloud Control Panel (UK).

You will use your credentials when you interact with OpenStack.

Installing The SDK

The OpenStack .NET SDK is installed by using the NuGet Package Manager, which is included with Visual Studio. You can install the SDK from the menu or from the Command window.

To use the Command windows, follow the menu path "Tools → Library Package Manager → Package Manager Console". After the Package Manager Console opens, type Install-Package openstack.net and press Enter to add openstack.net and its dependencies to your solution.

To use the graphical interface, follow the menu path "Tools → Library Package Manager → Manage NuGet Packages for Solution...", then search for "openstack.net" in the Online packages. Click the Install button and openstack.net and its dependencies will be added to your solution.

Sample Code

Sample code can be installed as well using the NuGet Package Manager. Search for "OpenStackSampleCode" and follow the installation method used for the SDK.

Getting A Server Up And Running

There are several parts to OpenStack computing. They include:

  • Provider and Identity
  • Servers
  • Cloud Files
  • Block Storage
  • Images
  • DNS Records
  • Load Balancers
  • Content Delivery Network (or CDN)
  • Databases
  • Monitoring

Some of the parts of OpenStack have names:

  • Identity = "Keystone"
  • Cloud Servers, or Compute = "Nova"
  • Cloud Files, or Object storage = "Swift"
  • Block Storage = "Cinder"
  • Images = "Glance"
  • Networking = "Neutron"
  • Dashboard, or Monitoring = "Horizon"

To get a server up and running, we need to use Keystone and Nova.

Keystone: Provider and Identity

The Provider is where you have your account. Examples include Rackspace, VMWare, Azure, etc. Obviously, you cannot use your Rackspace account to create (or "spin up") a server at Azure. By authenticating against your account at your provider you obtain your Identity, which allows you to work with your cloud objects. In other words, your Identity is who you are at the particular Provider.

Let’s take the example of Rackspace. In order to work with the cloud at Rackspace, you’ll need to visit their web site and establish your account. This includes things such as your name, email address, and a credit card number from which your monthly bill will be paid. Once this is done, you’ll have your user name and password, and you’ll also be issued an API Key.

The API Key, in combination with your user name, is used for authentication. Alternatively, you can use your user name and password, but there is a security risk; If someone learns your user name and password, they can log in to your account and change your password and effectively lock you out of your own account (meanwhile using your account). Using the API Key is safe, because you can log in to your account at any time and re-generate the API Key, making the previous API Key invalid.

When working with cloud objects, you can use your Identity in one of two ways:

  1. You can pass the Identity object along in every method call, or
  2. You can specify the Identity object when creating the Provider object, after which all calls using the Provider object will use the Identity object.

The following example (Example 1) demonstrates how to create an Identity object.

_cloudIdentity = new CloudIdentity(){Username = "username", APIKey = "api_key_goes_here"};

Example 1

Once the Identity object is created, it is then used to create the Provider object. The Provider object allows you to perform cloud tasks such as spin up a server, upload a file, etc.

The following example (Example 2) uses the Identity object to demonstrate how to create a Provider object. Note that the Identity object is included when the Provider is instantiated. This allows us to make subsequent calls without needing to include the Identity every time.

_provider = new CloudServersProvider(_cloudIdentity);

Example 2

Now that we have a Provider object, we can use it to perform cloud tasks (which are covered in detail later in this document), such as spin up a server.

The following example (Example 2) demonstrates how to spin up a server. It's not important (yet) that you fully understand this example, only that the principle is clearly understood: The Provider is where you do most of the work.

NewServer newServer = _provider.CreateServer(serverName, imageId, flavorId);

Example 3

At this point, we have a new server. But what do the parameters "imageId" and "flavorId" mean? That's covered in the next section, "Servers".

Nova: Servers

Servers are where you run your web site, your web services, your computing. One of the basic features of cloud computing is the ability to spin up additional servers as demand rises, and scale back if demand diminishes.

OpenStack allows you to programmatically spin up a server. A software developer can write a very few lines of code to do in minutes what used to take a hardware technician and network administrator days to do.

Depending on your provider, you may have many operating systems and virtual machine configurations from which to choose. In addition, certain software may be available.

For example, it may be possible to spin up a Microsoft Windows 2012 Server with 15 GB of RAM and 620 GB of DASD running Microsoft SQL Server 2012.

The operating system, software, amount of RAM and size of DASD are specified by using an Image, with optional Flavor and DiskConfig attributes.

For example, an Image may be "Windows Server 2012 with SQL Server 2012 with 2GB of RAM and 40 GB of disk". A Flavor may be "15 GB of RAM and 620 GB". By specifying this combination when spinning up a server (i.e. calling the method "CreateServer", as in Example 2), the provider will create a virtual server meeting these criteria.

The DiskConfig parameter has two valid values, "AUTO" and "MANUAL". "AUTO" will allocate disk storage of the size specified in the Flavor, e.g. 160 GB.

A value of "MANUAL" for DiskConfig will allocate enough disk storage to boot the operating system (e.g. 5 GB), while the remaining amount is available for formatting.

There are combinations that are not valid (i.e. they are mutually exclusive or not available for reasons of system requirements or minimal performance). For example, you cannot create a virtual machine running CentOS 5.9 with Microsoft SQL Server. Likewise, you cannot create a Windows Server 2008 virtual machine with 512 MB of RAM (system requirements require at least 1 GB of RAM). When retrieving an Image, it will include the properties "MinDisk" and "MinRAM", which specify the minimun disk needed (in gigabytes) and minimum RAM needed (in megabytes) for the Image. You can use that information to decide which Flavors are available for an Image.

Because of this, while spinning up a server is, indeed, "one line of code", you will typically need to investigate the valid combinations of OS, RAM and DASD before that one line. For example, the Image Id may be a 32-character string that does not have meaning outside of the SDK; you would need to see the associated Image Name to understand the value of the Image.

The following code example, Example 4, will show you a list of Images, their ID, and some related information.

IEnumerable<ServerImage> listOfImages = _provider.ListImagesWithDetails();
String hline = new String('-', 70);

foreach (ServerImage anImage in listOfImages) {
    Console.WriteLine(hline);
    Console.WriteLine("Image: {0}", anImage.Name);
    Console.WriteLine("\tID:\t{0}", anImage.Id);
    Console.WriteLine("\tDisk:\t{0} GB", anImage.MinDisk.ToString());
    Console.WriteLine("\tRAM:\t{0} MB", anImage.MinRAM);
}

Example 4

See table 1 for some examples of Images.

Image Id Image Name
cafe82a1-f3f9-4dec-b445-2b958604a170 CentOS 6.2
d59749af-cd74-4f08-abe0-34f1e643390e CentOS 6.0
bb8c27f9-f3cf-4606-9a88-8a2123e02290 Gentoo 13.2
8958846f-679b-454e-9232-20d3792fc5d7 OpenSUSE 12.3
32b7d027-8a40-458b-9e73-bd719d660df6 Arch 2013.6
81877a6e-9e87-4b1f-93f3-b176e25f3c4a Debian 7 (Wheezy)
05313f52-c19b-4640-b5ed-c7b8e8d17775 Windows Server 2008 R2 SP1 (with updates) + SQL Server 2012 Standard SP1

Table 1

Likewise, you may want to know and use valid values for Flavors.

Flavors refer to the combination of RAM and Disk Space for the server.

See table 2 for some examples of Flavors:

Flavor Id Flavor Name Disk Size RAM
2 512MB Standard Instance 20 GB 512 MB
3 1GB Standard Instance 40 GB 1 GB
4 2GB Standard Instance 80 GB 2 GB
5 4GB Standard Instance 160 GB 4 GB
6 8GB Standard Instance 320 GB 8 GB
7 15GB Standard Instance 640 GB 15 GB
8 30GB Standard Instance 1.2 TB 30 GB

Table 2

Important

It is important to note that when you call the method "CreateServer", OpenStack will launch the server creation at the endpoint (i.e. where your server will be) and continue. While the method may be successful, it is not finished running. For example, it may take a few minutes for the server to be fully operational, while the virtual system is provisioned, the operating system is loaded and booted, and any additional software (as part of the Image, described later) is loaded.

You can wait for the server to become operational by using the method "WaitForActive", which is covered in the document "OpenStack SDK for Microsoft .NET: Advanced Topics".

Given that, the following code (Example 4) will create an object of type "Identity", an object of type "Provider", and then create a server.

using System;
using System.Collections.Generic;

using net.openstack.Core.Domain;
using net.openstack.Core.Providers;
using net.openstack.Providers.Rackspace;
using net.openstack.Providers.Rackspace.Objects;

namespace GettingStarted
{
    class Program
    {

        public static CloudIdentity _cloudIdentity;
        public static CloudServersProvider _provider;

        public static void Main(string[] args)
        {

            try{

                Console.WriteLine("GettingStarted program execution has started...");

                // Create Identity
                Console.WriteLine("Creating Identity...");
                _cloudIdentity = new CloudIdentity(){Username = "your_username", APIKey = "your_APIKey"};

                // Create Provider
                Console.WriteLine("Creating Provider...");
                _provider = new CloudServersProvider(_cloudIdentity);

                // Spin up a new Server
                Console.WriteLine("Creating Server...");

                Metadata metaData = new Metadata(); // Add some metadata just because we can
                metaData.Add("Description", "Example 4 - Getting Started");

                string serverName = "Example4";
                string imageId = "48df4181-040e-4821-8723-d9e4ba908d2f";
                string flavorId = "3";

                NewServer newServer = _provider.CreateServer(serverName, imageId, flavorId, "MANUAL", metaData);    

                Console.WriteLine("Your Administrator password is: {0}", newServer.AdminPassword);

                Console.Write("Press any key to continue . . . ");
                Console.ReadKey(true);
            }
            catch(Exception ex){
                Console.WriteLine(ex.Message);
                Console.Write("Press any key to dismiss error and quit program . . . ");
                Console.ReadKey(true);
            }
        }

    }
}

Example 5

We've seen how to create a server using an off-the-shelf configuration by specifying an Image and a Flavor. But what if we could create custom images for our own, very specific needs? We could, say, create a server, install some software, then use that as a basis for all servers in the future.

Well, we can. In the next section, Creating And Using A Server Image, we'll learn how to create an Image of a server and then use that Image to create a new server.

Creating And Using A Server Image

One of the strengths of cloud computing includes the ability to add processing power by adding servers to the network. But quickly spinning up a server and then spending hours to configure it is antithetical to the idea of the cloud. A better way would be to configure one server (adding software, adjusting the server's configuration, etc), take a snapshot of it, and use that snapshot to create additional servers in the future.

That's what the Server Image does, and in this section you'll learn how to create and save your own images.

What might be included in an image?

After creating a server, you will typically install software. Examples might include a web service, a database server such as MySQL, etc. In addition to installing software, you may want to change system setting specific to your needs, including IIS pool sizes, database defaults, configuration files for your applications, etc.

Making these changes every time you spin up a new server can be a self-defeating time sink. It also opens the door to mistakes which may later be difficult to find.

Enter the Image.

The Image is quite simple: You create a server, make the configuration changes you want, then create an Image of that server. Later, you can use that saved Image to create more servers.

How to create and save an image

Creating an Image is easy; It is literally one line of code.

server.CreateSnapshot("imageNameGoesHere");

Example 6: Creating an Image of a server

You can also add metadata to the image, which is helpful when you have multiple images. For example, you may wish to add metadata that identifies a server as being related to a certain project or application. The code is straightforward; you specify a key and a value. You can add up to five metadata items to an Image.

image.AddMetadata("application", "StockTickerV3");

Example 7: Adding metadata to an Image

How to use an Image

Using an Image is something you've already done. In Section 2, we used a vendor-supplied ImageId in our method "CreateServer" to specify how to create our virtual server. To use your own Image, simply use the ImageId associated with i; it's that easy.

For example, going back to the code in Example 5, you simply supply the ImageId of your image when creating the server.

Storing Files In The Cloud

Files can, of course, be stored on a server. Typically, developers will use an FTP Server and client to upload and download files from a server.

With OpenStack .NET and the cloud, you can store files independent of them being stored on a server. You don't upload to and download from a server; you deal with the cloud.

In addition, you can put files into a Content Delivery Network, or CDN, for mass distribution -- more about that in Section 5, Creating A Content Delivery Network (CDN). For now, let's explore the process of uploading a file to the cloud.

Cloud files are stored in Containers, a virtual collection that you name. For example, you may have a container named "MarketingVideos" into which you upload a file named "ChicagoCampaign_Q22015.mp4".

The following example code demonstrates how to create a Container:

// Get a list of containers
// Notice: Cloud *Files* Provider instead of the previous
// Cloud *Servers* Provider.

CloudFilesProvider cfp = new CloudFilesProvider(_cloudIdentity);
cfp.CreateContainer("MarketingVideos");

Example 8: Creating a cloud files container

The following example code demonstrates how to upload a file into the Container created in Example 8:

cfp.CreateObjectFromFile("MarketingVideos", @"C:\ToBeUploaded\ChicagoCampaign_Q22015.mp4","ChicagoCampaignVideo");

Example 9: Uploading a video file to a cloud file Container

Notice that you can rename the file while you are uploading it.

After creating a container and uploading a file, the file is available for private use.

But what if you wish to make the file available publicly, to those outside of your network? To do that, you'll need to create a Content Delivery Network.

Creating A Content Delivery Network (CDN)

A Content Delivery Network, or CDN, is one of the more powerful features of cloud computing. A CDN allows a file to be uploaded and made publicly available. From that point, the file is replicated across the cloud by the provider. You have links with which to share access to the file, with the location of the file being spread across the provider's network, which helps with performance. Popular online services such as YouTube, Instagram, or Flickr use CDNs to increase their speed of delivery, as file access is directed to the nearest location instead of a central storage location.

The following code allows you to enable the CDN feature for a container. Note that the ttl (Time To Live) value of 259200 is 72 hours; this determines how long the CDN will wait before looking for new versions of files.

cfp.EnableCDNOnContainer("MarketingVideos", 259200);

Example 10:Enabling a CDN

Once a file container has been CDN-enabled, you then have links with which to share the files. You can use the container links and append the object names to share files. The following example demonstrates how to access the URI properties for a container.

// Get a list of containers
CloudFilesProvider cfp = new CloudFilesProvider(_cloudIdentity);

IEnumerable<ContainerCDN> listOfContainers = cfp.ListCDNContainers();
Console.WriteLine("--------- CDN Containers ------------");

foreach (ContainerCDN ctnr in listOfContainers) {

    if (ctnr.CDNEnabled) {

        Console.WriteLine("Container Name: {0}",ctnr.Name);
        Console.WriteLine("\tiOS Streaming URI: {0}", ctnr.CDNIosUri);
        Console.WriteLine("\tHTTPS URI: {0}", ctnr.CDNSslUri);
        Console.WriteLine("\tStreaming URI: {0}", ctnr.CDNStreamingUri);
        Console.WriteLine("\tHTTP URI: {0}", ctnr.CDNUri);

        IEnumerable<ContainerObject> listOfCO = cfp.ListObjects(ctnr.Name);

        foreach (ContainerObject co in listOfCO) {

            Console.WriteLine("Object details...");
            Console.WriteLine("--> {0} ({1})",co.Name,co.ContentType);
            Console.WriteLine("Link, URI --> {0}/{1}", ctnr.CDNUri, co.Name);
        }

    }
}

Example 11: Viewing CDN Containers and their contents

Creating A Network Of Servers

When creating multiple servers, it may be desirable to put them into networks. For example, you could spin up servers for development or testing, each in their own network (e.g. "DevNet" and "TestNet").

When putting servers into a network, you must create the network prior to creating the servers that will be a part of that network.

After that, adding a server to a network is a simple as specifying the network ID when creating the server.

When creating a network, you will need to specify the Classless Inter-Domain Routing (CIDR) blocks, for example, "10.1.0.0/24". You will also specify a name for the network, something that has meaning to you -- again, "DevNet" and "TestNet" might be good examples.

The following sample code shows how to create a network.

// Create Network Provider
Console.Write("Creating Network...");
CloudNetworksProvider cnp = new CloudNetworksProvider(cloudId);
CloudNetwork cn = cnp.CreateNetwork("10.1.0.0/24", networkname);
Console.Write("Done.\n");

Example 12: Creating a network

Now, given the above example, we use the network ID when creating a server. Note that, like the flavor ID, you'll need to somehow list the network IDs and choose one, or else copy and paste it into code. It's not something easy to remember.

// Create Provider
Console.Write("Creating Server {0}...", servername);
CloudServersProvider csp = new CloudServersProvider(cloudId);

// Create and populate the list of networks to join
List<Guid> networkList = new List<Guid>();
networkList.Add(new Guid(networkId));
IEnumerable<Guid> networks = networkList;

NewServer newServer = csp.CreateServer(servername, imageId, flavorId, region: region, networks: networks);
Console.Write("Done.\n");
Console.WriteLine("Administrator Password for new server {0} is {1}", servername, newServer.AdminPassword);

### END ###