For my first week working with Apache Cloudstack I wanted to get a quick feel for it. Going through the documentation proved to be a little daunting, with a quick installation guide, an advanced installation guide, an administration guide, a developer guide, a cloudbridge guide…My head went spinning really fast. Then DevCloud came to the rescue.

Edison Su one of the Cloudstack developer for Citrix came up with a fully configured virtual box appliance that contained the cloudstack management server and took advantage of nested virtualization to actually spin up virtual machines within the appliance started in cloudstack. A clever packaging aimed at developers trying to test their code, but a packaging that can also be used to get a quick hands-on tour of the system.

I was mostly interested in couple things: Start an instance via the GUI, play with the API and check the EC2 compatibility.

Playing with the GUI and accessing DevCloud:
That was the easiest, as soon as the appliance is imported, you can follow Edison's instructions from the wiki and get a VM running. DevCloud is setup with a NAT interface, and a few ports are forwarded. The CS GUI is therefore available at http://localhost:8080/client with admin/password as the default login credentials. The trick was to enable the zone, wait for the system VMs to start and then in the instance creation wizard to not select a disk offering. This is one of the limitations of DevCloud. Surely this appliance will get better and I can foresee how most bugs discussed in the wiki will be fixed.
With port 22 being forwarded to 2222, you can ssh to Devcloud with:

$ ssh -p 2222 root@localhost
root@localhost's password:
Welcome to Ubuntu 12.04 LTS (GNU/Linux 3.2.0-23-generic-pae i686)

Documentation: https://help.ubuntu.com/
System information as of Fri Jul 20 07:07:46 PDT 2012

System load: 0.85 Users logged in: 0
Usage of /: 32.2% of 5.57GB IP address for eth0: 10.0.2.15
Memory usage: 54% IP address for eth1: 192.168.56.101
Swap usage: 0% IP address for xenbr0: 10.0.2.15
Processes: 124 IP address for xapi0: 169.254.0.1

Graph this data and manage this system at https://landscape.canonical.com/

Last login: Tue Jul 17 13:45:32 2012 from 10.0.2.2
root@devcloud:~#

Since this is a Xen kernel we can check which VMs are running within DevCloud (VMs within a VM):

root@devcloud:~# xe vm-list
uuid ( RO) : c2f3acb6-cb95-6dbf-bcfb-b0407cda097b
name-label ( RW): r-5-VM
power-state ( RO): running

uuid ( RO) : 93a98ad6-c221-5b45-8c4c-3408bbd21a46
name-label ( RW): i-2-9-VM
power-state ( RO): running

uuid ( RO) : d640ba11-876c-b4d3-8bc8-660c44bff924
name-label ( RW): s-1-VM
power-state ( RO): running

uuid ( RO) : f01b195e-074b-e8f2-f8b1-b2c493070c8a
name-label ( RW): Control domain on host: devcloud
power-state ( RO): running

uuid ( RO) : 4440f913-3bbf-c048-e948-02c195b6e78f
name-label ( RW): v-2-VM
power-state ( RO): running

We see Dom0, the secondary storage VM, the proxy VMs, the router VM and the instance that was started (i-2-9-VM)

Using the API:
Cloudstack has a very rich and powerful API, well documented at http://download.cloud.com/releases/3.0.0/api_3.0.0/TOC_Root_Admin.html , to get a feel for it, the best is probably to create a user with admin privileges in the ROOT domain. To do this, use the GUI, and go to Accounts , click on the admin account, and then click on View Users, you should then see the Add user icon. Once you have added the user, click on its username and then find the generate keys icon. This will create an API Key and Secret Key for that user. Alternatively, you could just generate keys for the default admin user. The last thing you need to get going is a Cloudstack client library. Since I like Python, a quick Google search led me to https://github.com/jasonhancock/cloudstack-python-client . A git clone and sudo python ./setup.py later, I was ready to run my first calls against the cloudstack API.

I used the example from Jason Hancock and modified it to list the Zone:

#!/usr/bin/python

import CloudStack
import pprint

api = 'http://localhost:8080/client/api'
apikey = 'wHTzTA7o36L9atVVkTSeT7dqXYCnC_3CT4KlhdZtPsLiL_-x0vhM94vrnYz9CYZhsfL74dHl4HRWnyAsKS2ecA'
secret = '4MjMPs-N9SfZ7O4VPdZGqLgrVQcoEU3B7geF8KPTHPbD96WGbjcfzrHKHPA_v2XFMetrtNegGtrYrIkwCrQmTw'

cloudstack = CloudStack.Client(api, apikey, secret)

zones = cloudstack.listZones()
pprint.pprint(zones)

Which resulted in:

[

{u'allocationstate': u'Enabled', u'dhcpprovider': u'VirtualRouter', u'dns1': u'8.8.8.8', u'domainid': 1, u'domainname': u'ROOT', u'id': u'e1bfdfaf-3d9b-43d4-9aea-2c9f173a1ae7', u'internaldns1': u'10.0.2.3', u'name': u'devcloud', u'networktype': u'Basic', u'securitygroupsenabled': True, u'zonetoken': u'19bc5c3c-3dd3-328a-96ab-5a7e02dcafb1'}
]

Of course what I wanted to do was to start an instance within DevCloud. Checking the API reference for deployVirtualMachine (http://download.cloud.com/releases/3.0.0/api_3.0.0/root_admin/deployVirtualMachine.html) I found that I needed the ids of the Zone, the service offering and the template. The Zone id is listed above. Thankfully, the API has a listServiceOfferings and a listTemplates. A little Python:

filter=

{'templatefilter':'featured'}
templates = cloudstack.listTemplates(filter)
pprint.pprint(templates)

services = cloudstack.listServiceOfferings()
pprint.pprint(services)

And I was able to get the missing ids. I could now call deployVirtualMachine by building a little dictionary:

job = cloudstack.deployVirtualMachine({
    'serviceofferingid': 'ef2537ad-c70f-11e1-821b-0800277e749c',
    'templateid':        '13ccff62-132b-4caf-b456-e8ef20cbff0e',
    'zoneid':            'e1bfdfaf-3d9b-43d4-9aea-2c9f173a1ae7'
})

You may not have enough RAM to start multiple VMs, so make sure you kill all running instances (via the GUI until you figure out the proper API call).

This is terrific, we have a working Cloudstack setup, we can start an instance, even though a toy one. We can use the native API. But what about the compatibility with EC2 ? So far, this is provided by an additional server called CloudBridge (http://docs.cloud.com/CloudBridge_Documentation). CloudBridge needs to run on a separate machine than the management server even though we can reasonably expect it to be merge with the main Cloudstack server in the future. I decided to setup a new Virtual Box VM using CentOS 6.2 and install Cloudbridge in it in a single node configuration (http://docs.cloud.com/CloudBridge_Documentation/Installing_Single-Node_CloudBridge). The issue was that DevCloud comes with a NAT interface and that I did not want to mess the network offering that was setup, so I decided to add a host-only network interface to DevCloud, to build a private network between the host, DevCloud and the Cloudbridge VM. In Virtual Box this is easily done, go to Preferences > Network and add a host-only network. You will need to configure the address range of the DHCP server by clicking on the screwdriver icon of the VBox GUI. What we end up with is a virtual switch running on the host, and the two VMs attached to that switch.

                                     ____eth0 (CloudBridge VM): 192.168.56.102

                                     ___Potentially attached other VMs to this virtual network (e.g Other Compute Agent)
vboxvnet0 (interface on the host)----
                                     ____eth1 (DevCloud VM): 192.168.56.101

                                               ____xenbr0 (DevCloudVM)___eth0 (10.0.2.15)

                                               _______________vif2.0 (10.0.2.2) (e.g DevCloud Guests started by Cloudstack)

By adding such an interface, I now have the following in the DevCloud guest:

eth0 Link encap:Ethernet HWaddr 08:00:27:7e:74:9c
inet addr:10.0.2.15 Bcast:10.0.2.255 Mask:255.255.255.0
...

eth1 Link encap:Ethernet HWaddr 08:00:27:df:00:00
inet addr:192.168.56.101 Bcast:192.168.56.255 Mask:255.255.255.0
...

The CloudBridge VM will be 192.168.56.102 (it could be different depending on your configuration), and a route exists between the two VMs and the host.

You need to register the user you created earlier with CB, this can be done with the cloud-bridge-register script on the CB server like this:

root@manager sebgoa# cloud-bridge-register -a 5qjf5cJVGdGkAN-kf_kK3VTDR_4Xrj29U6o1M5kSjc6ksVTA14zNoxJZIE7a3iy17WnwFcsXnZU5MVpMSQK7Fw -s 7_gonVM3ZJrTWcwdQUHuGRUtNmbGFneFRWg-TF7DPqk8Z_aCHYGmVhdiVUUQSLqdhQFqGbSAEzW7882N9JSl7Q -c /home/sebgoa/Desktop/cert.pem -u http://192.168.56.102:8090/bridge

http://192.168.56.102:8090/bridge
It could also be done outside of the CB VM by making the proper http request which calls SetUserKeys and SetUserCert.

Couple things in the CloudBridge (CB) setup need to be clarified:
I will use an EC2 client library to make calls to CB, which will forward these calls to the CS server, and map the ec2 api to the appropriate CS api. This also means that CB needs to know how to map the standard EC2 instance types (e.g m1.small, m1.large etc..) to the Compute Offerings in CS. This was not clear to me while I was doing the setup and a bug confused me even more. The fact is that CB has an API itself and that you can make calls to register users and map offerings: http://docs.cloud.com/CloudBridge_Documentation/Utility_Commands_for_CloudBridge . The documentation is going to be corrected, but the proper way to make a call to CB can be checked by looking at /usr/bin/cloud-bridge-register, a small python script used to register the users. The same logic can be used to make a properly signed request to map m1.small to tinyOffering in DevCloud, you can check my dirty hack at http://pastebin.com/yiSeMt2M, don't try to use my keys, it won't work for you (smile)

Make sure that port 8090 is open or just turn off iptables.

The keys are the same as before. The cert is added but I believe this is only used for SOAP calls, so as long as you only use REST EC2 API you can provide a dummy cert. If you actually look at the script you will also note that the keys and the cert are added in two separate calls, even though the cert is actually a mandatory option. I think that some optimization could be done here.

Once the user is registered in CB and that the offer mapping has been entered you can use your favorite EC2 client to make calls to the cloudbridge. In my case, I love boto, so I modified an existing boto example to point to the CB endpoint and I specified the keys:

region = boto.ec2.regioninfo.RegionInfo(name="ROOT",endpoint="192.168.56.102")
apikey = '5qjf5cJVGdGkAN-kf_kK3VTDR_4Xrj29U6o1M5kSjc6ksVTA14zNoxJZIE7a3iy17WnwFcsXnZU5MVpMSQK7Fw'
secretkey = '7_gonVM3ZJrTWcwdQUHuGRUtNmbGFneFRWg-TF7DPqk8Z_aCHYGmVhdiVUUQSLqdhQFqGbSAEzW7882N9JSl7Q'

def main():
'''Establish connection to EC2 cloud'''
conn =boto.connect_ec2(aws_access_key_id=apikey,
aws_secret_access_key=secretkey,
is_secure=False,
region=region,
port=8090,
path="/bridge",
api_version="2010-11-15")

Note the path /bridge , and the api version. Hopefully we will soon see support for more recent EC2 api. Once the connection is made, you can start testing the ec2 api compatible with cloudstack. I started an instance with:

        '''Get list of images that I own'''
        images = conn.get_all_images()
        myimage = images0
        '''Pick an instance type'''
        vm_type='m1.small'
        reservation = myimage.run(instance_type=vm_type,security_groups='default')

Recall here that m1.small will point to tinyOffering in DevCloud.

And that's it, a working Cloudstack install, with API calls and EC2 compatibility.

  • No labels