Search This Blog

Showing posts with label cloudserver. Show all posts
Showing posts with label cloudserver. Show all posts

Saturday, August 11, 2012

cloudserver script doesn't work anylonger after installing novaclient

I have played with the FirsGen Rackspace cloud on my box. It was working fine. Some info about how to start with it can be found here rackspace-cloudservers .

At some point I have started using the Openstack nova tool to interact with the Rackspace NextGen cloud to run some tests. Once I was done I returned to the openstack tool and discoved that it stopped to work.

Problem

For every comamnd I run i got alwasys the same error message. An example output.
$ /usr/bin/cloudservers --username user --apikey 123  list
Traceback (most recent call last):
  File "/usr/bin/cloudservers", line 9, in module
    load_entry_point('python-cloudservers==1.0a5', 'console_scripts', 'cloudservers')()
  File "/usr/lib/pymodules/python2.7/cloudservers/shell.py", line 413, in main
    CloudserversShell().main(sys.argv[1:])
  File "/usr/lib/pymodules/python2.7/cloudservers/shell.py", line 127, in main
    args.func(args)
  File "/usr/lib/pymodules/python2.7/cloudservers/shell.py", line 279, in do_list
    print_list(self.cs.servers.list(), ['ID', 'Name', 'Status', 'Public IP', 'Private IP'])
  File "/usr/lib/pymodules/python2.7/cloudservers/shell.py", line 402, in print_list
    pt.printt(sortby=fields[0])
  File "/usr/local/lib/python2.7/dist-packages/prettytable.py", line 163, in __getattr__
    raise AttributeError(name)
AttributeError: printt
Solution

After debugin the prettytable.py code it turned out that there is not such a function like printt. Further research confirmed this [1]. The fix this I have changed the code of cloudserver module on my PC. The new code after changes is listed below.

# vim +399 /usr/lib/pymodules/python2.7/cloudservers/shell.py

def print_list(objs, fields):
    pt = prettytable.PrettyTable([f for f in fields], caching=False)
    pt.aligns = ['l' for f in fields]
    for o in objs:
        pt.add_row([getattr(o, f.lower().replace(' ', '_'), '') for f in fields])

    # pt.printt(sortby=fields[0])
    print pt.get_string(sortby=fields[0])
References
  1. http://code.google.com/p/prettytable/issues/detail?id=14&q=printt
  2. https://answers.launchpad.net/nova/+question/198709

  3. Other examples where the code was broken as well
  4. https://github.com/calebgroom/clb/issues/24
  5. http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=673790

Sunday, July 29, 2012

How to clean and delete multiple cloud servers after a failed test

The best think about open cloud API is that it is easy accessible and can be easily scripted around. For exmaple during one of my tests I created multiple cloud servers but my job failed and didn't delete them before the exception was thrownd.

Problem

How to extract cloud server names from the log file and how to delted all of them from the accout.

$ python performance-single-cs.py-t 1 -s 25 -u user -k key  run | tee log.$(date +%s).txt
$ cat log*.txt
[ 1][  ] starting test nr 1, creating 25 cloud server, please wait ...
[ 1][ 1] created image: {'flavor': 1, 'image': 112, 'name': 'test7945'}
[ 1][ 2] created image: {'flavor': 1, 'image': 112, 'name': 'test7948'}
[ 1][ 3] created image: {'flavor': 1, 'image': 112, 'name': 'test7951'}
[ 1][ 4] created image: {'flavor': 1, 'image': 112, 'name': 'test7954'}
[ 1][ 5] created image: {'flavor': 1, 'image': 112, 'name': 'test7958'}
[ 1][ 6] created image: {'flavor': 1, 'image': 112, 'name': 'test7961'}
[ 1][ 7] created image: {'flavor': 1, 'image': 112, 'name': 'test7965'}
[ 1][ 8] created image: {'flavor': 1, 'image': 112, 'name': 'test7969'}
[ 1][ 9] created image: {'flavor': 1, 'image': 112, 'name': 'test7972'}
[ 1][10] created image: {'flavor': 1, 'image': 112, 'name': 'test7976'}
[ 1][11] created image: {'flavor': 1, 'image': 112, 'name': 'test8050'}
[ 1][12] created image: {'flavor': 1, 'image': 112, 'name': 'test8054'}
[ 1][13] created image: {'flavor': 1, 'image': 112, 'name': 'test8059'}
[ 1][14] created image: {'flavor': 1, 'image': 112, 'name': 'test8063'}
[ 1][15] created image: {'flavor': 1, 'image': 112, 'name': 'test8068'}
[ 1][16] created image: {'flavor': 1, 'image': 112, 'name': 'test8072'}
[ 1][17] created image: {'flavor': 1, 'image': 112, 'name': 'test8077'}
[ 1][18] created image: {'flavor': 1, 'image': 112, 'name': 'test8082'}
[ 1][19] created image: {'flavor': 1, 'image': 112, 'name': 'test8086'}
[ 1][20] created image: {'flavor': 1, 'image': 112, 'name': 'test8091'}
[ 1][21] created image: {'flavor': 1, 'image': 112, 'name': 'test8117'}
[ 1][22] created image: {'flavor': 1, 'image': 112, 'name': 'test8192'}
[ 1][23] created image: {'flavor': 1, 'image': 112, 'name': 'test8197'}
[ 1][24] created image: {'flavor': 1, 'image': 112, 'name': 'test8202'}
[ 1][25] created image: {'flavor': 1, 'image': 112, 'name': 'test8208'}
[ 1][ 1] cloud server build [test7945] created in 298.427304 seconds / 4.9737884 minutes
[ 1][ 2] cloud server build [test7948] created in 298.331735 seconds / 4.97219558333 minutes
[ 1][ 3] cloud server build [test7951] created in 298.268271 seconds / 4.97113785 minutes
[ 1][ 4] cloud server build [test7954] created in 298.469954 seconds / 4.97449923333 minutes
[ 1][ 5] cloud server build [test7958] created in 298.202301 seconds / 4.97003835 minutes
[ 1][ 6] cloud server build [test7961] created in 297.702382 seconds / 4.96170636667 minutes
[ 1][ 7] cloud server build [test7965] created in 298.051012 seconds / 4.96751686667 minutes
[ 1][ 8] cloud server build [test7969] created in 297.3658 seconds / 4.95609666667 minutes
[ 1][ 9] cloud server build [test7972] created in 296.993362 seconds / 4.94988936667 minutes
[ 1][10] cloud server build [test7976] created in 296.810522 seconds / 4.94684203333 minutes
[ 1][11] cloud server build [test8050] created in 226.269396 seconds / 3.7711566 minutes
[ 1][12] cloud server build [test8054] created in 226.051247 seconds / 3.76752078333 minutes
[ 1][14] cloud server build [test8063] created in 225.04139 seconds / 3.75068983333 minutes
[ 1][15] cloud server build [test8068] created in 224.326799 seconds / 3.73877998333 minutes
[ 1][16] cloud server build [test8072] created in 223.051956 seconds / 3.7175326 minutes
[ 1][17] cloud server build [test8077] created in 221.830032 seconds / 3.6971672 minutes
[ 1][18] cloud server build [test8082] created in 219.514883 seconds / 3.65858138333 minutes
[ 1][19] cloud server build [test8086] created in 218.35139 seconds / 3.63918983333 minutes
[ 1][20] cloud server build [test8091] created in 216.172884 seconds / 3.6028814 minutes
[ 1][21] cloud server build [test8117] created in 193.915105 seconds / 3.23191841667 minutes
[ 1][13] cloud server build [test8059] created in 328.421036 seconds / 5.47368393333 minutes
[ 1][22] cloud server build [test8192] created in 197.893329 seconds / 3.29822215 minutes
[ 1][23] cloud server build [test8197] created in 196.71745 seconds / 3.27862416667 minutes
[ 1][24] cloud server build [test8202] created in 263.305984 seconds / 4.38843306667 minutes
[ 1][25] cloud server build [test8208] created in 260.425359 seconds / 4.34042265 minutes

Solution

For a single log file

$ cat log.*.txt | grep "image':" | cut -d':' -f5 | tr '}' ' ' | grep -v created > tmp
echo > 'set -x' >  delete-all-cs.sh
cat tmp | xargs -I cs_name echo 'cloudservers --username user --apikey key delete cs_name' >> delete-all-cs.sh
bash delete-all-cs.sh

When we have multiple log files

$ cat << END > aux_script.sh
cat $1 | grep "image':" | cut -d':' -f5 | tr '}' ' ' | grep -v created > tmp
cat tmp | xargs -I cs_name echo 'cloudservers --username user --apikey key delete cs_name' >> delete-all-cs.sh
END

$ for i in log.*.txt ; do echo $i; ./aux_script.sh $i;  done
$ bash -x delete-all-cs.sh

Summary and results discussion

The solution with 'xargs' works pretty well for relatively small number of servers to delete. As each cloud server is deleted in a single cloudserver run there is no parallelism involved.

An interesting solution could be built with a help of a parallel tool [3]. It could allow us to execute multiple commands in parallel and achieve a much better timing results. Of course to make it work we would have to take into consideration the API limitations and design some workarounds it.

References
  1. https://github.com/rtomaszewski/cloud-performance
  2. http://www.cyberciti.biz/faq/linux-unix-bsd-xargs-construct- argument-lists-utility/
  3. https://savannah.gnu.org/projects/parallel/

Saturday, July 28, 2012

How long does a cloud API may return a cached results

I have been playing with the Rackspace first generation cloud API library/tool (python-cloudservers [1] ) and simulated API calls to create and destroy and list cloud servers.

Problem

At the time of this writing I haven't run into any issues with the create cloud API call. Although I have found some strange behavior when I tried to check status of the newly created cloud server after.

Playing with the tool I wrote [2] for testing I saw that the cloud API call to get a list of all cloud servers immensely relays on cached data that we often get.

GET /servers/detail  # List all servers (all details) [3]

Test

When testing and trying to determine how long it takes to create a cloud sever I got thes results:

# during a week 
$ python performance-single-cs.py -s 2 -u  user -k key  run 
[ 0] creating image: {'flavor': 1, 'image': 112, 'name': 'csperform1343469777'}
[ 0] cloud server build [csperform1343469777] created in 226.428314 seconds / 3.77380523333 minutes
[ 1] creating image: {'flavor': 1, 'image': 112, 'name': 'csperform1343470005'}
[ 1] cloud server build [csperform1343470005] created in 288.115938 seconds / 4.8019323 minutes
[ 2] creating image: {'flavor': 1, 'image': 112, 'name': 'csperform1343471011'}
[ 2] cloud server build [csperform1343471011] created in 1841.598305 seconds / 30.6933050833 minutes

# on Sunday 
$ python performance-single-cs.py -t 1 -s 13 -u hugoalmeidauk -k 391c77192480cbb9969d0514b3daebe1  run
[ 1][  ] starting test nr 1, creating 13 cloud server, please wait ...
[ 1][ 1] created image: {'flavor': 1, 'image': 112, 'name': 'csperform1343582734'}
[ 1][ 2] created image: {'flavor': 1, 'image': 112, 'name': 'csperform1343582738'}
[ 1][ 3] created image: {'flavor': 1, 'image': 112, 'name': 'csperform1343582741'}
[ 1][ 4] created image: {'flavor': 1, 'image': 112, 'name': 'csperform1343582744'}
[ 1][ 5] created image: {'flavor': 1, 'image': 112, 'name': 'csperform1343582747'}
[ 1][ 6] created image: {'flavor': 1, 'image': 112, 'name': 'csperform1343582751'}
[ 1][ 7] created image: {'flavor': 1, 'image': 112, 'name': 'csperform1343582754'}
[ 1][ 8] created image: {'flavor': 1, 'image': 112, 'name': 'csperform1343582758'}
[ 1][ 9] created image: {'flavor': 1, 'image': 112, 'name': 'csperform1343582761'}
[ 1][10] created image: {'flavor': 1, 'image': 112, 'name': 'csperform1343582835'}
[ 1][11] created image: {'flavor': 1, 'image': 112, 'name': 'csperform1343582839'}
[ 1][12] created image: {'flavor': 1, 'image': 112, 'name': 'csperform1343582843'}
[ 1][13] created image: {'flavor': 1, 'image': 112, 'name': 'csperform1343582847'}
[ 1][ 1] cloud server build [csperform1343582734] created in 149.491952 seconds / 2.49153253333 minutes
[ 1][ 2] cloud server build [csperform1343582738] created in 148.614413 seconds / 2.47690688333 minutes
[ 1][ 3] cloud server build [csperform1343582741] created in 147.810013 seconds / 2.46350021667 minutes
[ 1][ 4] cloud server build [csperform1343582744] created in 147.27588 seconds / 2.454598 minutes
[ 1][ 5] cloud server build [csperform1343582747] created in 145.799047 seconds / 2.42998411667 minutes
[ 1][ 6] cloud server build [csperform1343582751] created in 144.760795 seconds / 2.41267991667 minutes
[ 1][ 7] cloud server build [csperform1343582754] created in 143.3738 seconds / 2.38956333333 minutes
[ 1][ 8] cloud server build [csperform1343582758] created in 141.850991 seconds / 2.36418318333 minutes
[ 1][ 9] cloud server build [csperform1343582761] created in 140.177985 seconds / 2.33629975 minutes
[ 1][10] cloud server build [csperform1343582835] created in 157.222253 seconds / 2.62037088333 minutes
[ 1][11] cloud server build [csperform1343582839] created in 155.36349 seconds / 2.5893915 minutes
[ 1][12] cloud server build [csperform1343582843] created in 153.28229 seconds / 2.55470483333 minutes
[ 1][13] cloud server build [csperform1343582847] created in 151.02232 seconds / 2.51703866667 minutes
Results

In average the time between the library API call to create a cloud server and then multiple API calls to verify that this server is successfully built took about 3 to 4 minutes during the week and 2 to 3 min at the weekend. In the worst case when the cache was involved the cloud server API took up to 30min before the data were invalidated and refreshed.

Analysis  

I don't think it is cache problem only. When looking at the python-cloudservers [1] library we can notice that:
  • The documentation has a warning [4]
find(**kwargs) Find a single item with attributes matching **kwargs.
This isn’t very efficient: it loads the entire list then filters on the Python side.
  • The python-cloudservers code shows that it uses only the 'GET /servers/detail' API call instead of  'GET /servers/id' [5]
A code analyses will not be provided but for interested readers they can take a lock at these files to confirm:
/usr/lib/pymodules/python2.7/cloudservers/__init__.py
/usr/lib/pymodules/python2.7/cloudservers/base.py
/usr/lib/pymodules/python2.7/cloudservers/servers.py


References
[1] https://github.com/rackspace/python-cloudservers
[2] https://github.com/rtomaszewski/cloud-performance
[3] http://docs.rackspace.com/servers/api/v1.0/cs-devguide/content/List_Servers-d1e1730.html
[4] http://packages.python.org/python-cloudservers/ref/servers.html#classes
[5] http://docs.rackspace.com/servers/api/v1.0/cs-devguide/content/Get_Server_Details-d1e2143.html

Friday, July 27, 2012

Stale data and caching problem when dealing with cloud API responses

Because the Rackspace cloud API is using caching extensively you have to write a code that is able to handle a stale HTTP data and be able to resent the request if needed.

Example 

A simple example that sometimes works and another time may not work because the API HTTP response contains 404 status code.

from cloudservers import CloudServers
cs=CloudServers(user, key)
cs.authenticate()
sm=cs.servers
server=sm.create(name, image, flavor)
sm.find( name=_server.name )

The cloud 'find' function [1] raises exception NotFound even though we know that the server is there and it shouldn't. 

Traceback (most recent call last):
  File "performance-single-cs.py", line 175, in module
    Main().run()
  File "performance-single-cs.py", line 172, in run
    self.test_performance(user,key)
  File "performance-single-cs.py", line 134, in test_performance
    t.test_perf_single_cs(1)
  File "performance-single-cs.py", line 105, in test_perf_single_cs
    status=self.check_cs_status(server)
  File "performance-single-cs.py", line 45, in check_cs_status
    server=sm.find( name=_server.name )
  File "/usr/lib/pymodules/python2.7/cloudservers/base.py", line 50, in find
    raise NotFound(404, "No %s matching %s." % (self.resource_class.__name__, kwargs))


References

[1] http://packages.python.org/python-cloudservers/ref/servers.html#classes

Tuesday, July 24, 2012

Rackspace python-cloudservers debugging

For the first generation of Rackspace cloud there is a cli tool and a python library [1].
The source code can the tool can be found on github [2].

Problem description

After successful installation of this tool I run into the follow error below.
 
# cat /etc/issue
Ubuntu 11.04 \n \l
# aptitude install python-rackspace-cloudservers

$ cloudservers --username user --apikey 391c7...be1  show 10197279
Traceback (most recent call last):
  File "/usr/bin/cloudservers", line 9, in 
    load_entry_point('python-cloudservers==1.0a5', 'console_scripts', 'cloudservers')()
  File "/usr/lib/pymodules/python2.7/cloudservers/shell.py", line 409, in main
    CloudserversShell().main(sys.argv[1:])
  File "/usr/lib/pymodules/python2.7/cloudservers/shell.py", line 123, in main
    self.cs.authenticate()
  File "/usr/lib/pymodules/python2.7/cloudservers/__init__.py", line 60, in authenticate
    self.client.authenticate()
  File "/usr/lib/pymodules/python2.7/cloudservers/client.py", line 79, in authenticate
    resp, body = self.request(self.AUTH_URL, 'GET', headers=headers)
  File "/usr/lib/pymodules/python2.7/cloudservers/client.py", line 34, in request
    body = json.loads(body) if body else None
  File "/usr/lib/python2.7/json/__init__.py", line 326, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python2.7/json/decoder.py", line 360, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib/python2.7/json/decoder.py", line 378, in raw_decode
    raise ValueError("No JSON object could be decoded")
ValueError: No JSON object could be decoded

Troubleshooting


Investigating the stacktrace we see that there are various method called before the error was reported. Looking at the stack from bottom up we see that the the code gets interested around lines 12 and 13.

$ sed -n 79p  /usr/lib/pymodules/python2.7/cloudservers/client.py
        resp, body = self.request(self.AUTH_URL, 'GET', headers=headers)

$ grep AUTH_URL /usr/lib/pymodules/python2.7/cloudservers/client.py 
    AUTH_URL = 'https://auth.api.rackspacecloud.com/v1.0'
        resp, body = self.request(self.AUTH_URL, 'GET', headers=headers)

We see that the URL is hard coded in python code. Because my cloud account is base in London (my cloud files and cloud server provisioning regions are in London ) this URL is wrong. More info about the authentication point can be found in the official doc [3].

An easy fix for this requires to change the URL to a new one:

https://lon.auth.api.rackspacecloud.com/v1.0

References

[1] http://packages.python.org/python-cloudservers/index.html
[2] https://github.com/rackspace/python-cloudservers
[3]
http://docs.rackspace.com/api/
http://docs.rackspace.com/servers/api/v1.0/cs-devguide/content/Overview-d1e70.html

[4] http://www.dimitrioskouzisloukas.com/blog/index.php?blog=2&title=authenticate_with_cloudservers_to_the_lo&more=1&c=1&tb=1&pb=1