Basic CRUD with Openstack Python V2.x clients

Last week I had this shiny assignment by a company here for a thesis interview to build some Python scripts using Openstack Python clients. It made me create some code which eventually got me through.  The recent upgrade of Openstack Python clients from API v1 to 2 have left most of the parts undocumented or carefully shredded here and there, so here you go.

Keystone: authenticate

In case you are just playing around with the default project domains, this should return the auth sessions.  

from keystoneauth1.identity import v3
from keystoneauth1 import session

def authenticate_and_return_session(auth_url='', username=None, password=None):
    auth = v3.Password(
        auth_url=auth_url, username=username,
        password=password, project_name="demo", user_domain_id="default",
    return session.Session(auth=auth)

Keystone: list projects

from keystoneclient.v3 import client as keystoneclient

def list_projects(session=None):
    keystone = keystoneclient.Client(session=session)
    return keystone.projects.list()

Glance: list images and return the first one

You might want to now list out all the images to select what to chose

from glanceclient import Client

def list_images(session=None):
    # now check out images from glance

    glance = Client('2', session=session)

    image_ids = []
    for image in glance.images.list():

    print('{0} Images found'.format(len(image_ids)))
    # Return the first image id
    return image_ids[0]

Nova: list flavors and return the `tiny` one

def get_your_flavor(flav_name='m1.tiny'):
    nova = novaclient.Client(2.1, session=sess)
    return nova.flavors.find(name=flav_name)

Neutron: Create network

This is one of the important steps, here we are trying to create a custom network and subnet on which our VM should reside

from neutronclient.v2_0 import client
def create_network(session, network_name='test_net')
    neutron = client.Client(session=session)

    return neutron.create_network(
        body={"network": {"name": network_name, "admin_state_up": True}}

Neutron: Create your custom subnet

def create_subnet(neutronclient=None, net=None, cidr=''):
    return neutronclient.create_subnet(
            'subnet': {
                'name': 'test_sub', 'network_id': net['network']['id'],
                'ip_version': 4, 'cidr': cidr, 'enable_dhcp': True

Neutron: Connect new subnet to the default router

This would add an interface to the default router to our new subnet

sub = create_subnet(neutronclient, net=net)
        'subnet_id': sub['subnet']['id']

Nova: Create your instance, connect your NIC card to new network

def create_instance(instance_ip_address=''):
    nics = [
            'net-id': net['network']['id'],
            'v4-fixed-ip': '{0}'.format(instance_ip_address)
    instance = nova.servers.create(
        name='api-test', image=image, flavor=flav, nics=nics
    if instance:
        print('Created: {0}'.format(instance))

thats it! You can see a better version here though. Leave a comment if you found this interesting.


DetailView on Django REST – multiple methods

Long time since I wrote something on Django, but today it surprised me again with its flexibility. Let me put it down here. Remember the traditional DetailView ?

Example from:

from django.views.generic.detail import DetailView
from articles.models import Article<img src="blob:" alt="Selection_407.png" class="alignnone size-full wp-image-media-2"/>

class ArticleDetailView(DetailView):

    model = Article

    def get_object(self): 
            return Article.objects.get(pk=self.kwargs.get('pk'))

Setting this thing up in Angular to retrieve details of an Article, I used to follow something similar:

from articles.models import Article
from django.http import Http404

class ArticleDetailView(generics.RetrieveAPIView):

    model = Article
    serializer_class = ArticleDetailsSerializer
    queryset = Article.objects.all() 

    def get_object(self): 
            return Article.objects.get(pk=self.kwargs.get('pk'))
        expect ValueError:
            return Http404

I was looking through the documentation agian , and I see that the entire thing can be done in like 3 lines. Take a look:

from articles.models import Article

class ArticleDetailView(generics.RetrieveAPIView):

    model = Article
    serializer_class = ArticleDetailsSerializer
    queryset = Article.objects.all() 

Note: This should work only if you have Article primary key received on as pk. ie, something like this in your

from django.conf.urls import url

from article.views import ArticleDetailView

urlpatterns = [
    url(r'^article/(?P<pk>[\w]+)/$', ArticleDetailView.as_view(), name='article-list'),

In case you do not want to send in the primary key, you can provide the custom slug name using the attribute lookup_fields in your view definition. Read more here:

An example request to the URL would be Django for life, Enjoy humans.

Surprise from Python on new years eve, 2016

Alright, so another usual night and I was trying to figure out a strange behavior with a Python class I was working. Looks like I had OOP lectures only in C++, and things are little bit different here. So here you go!

I had this strange class method here described as:

class BenchmarkResults(object):

    def _generate_db_entries(cls, tests, skip_aggregated=False, parent=None, test_table = []):
         # This function recursively calls _generate_db_entries with
         # test_table param set to a list 

and this was processing in a JSON file from one of my POST API and doing some crazy stuff. The API calls this class like

class BotReportView(APIView):
    def post(self, request, format=None):
        test_data_results = BenchmarkResults(json.load(self.request.FILES.get('test_data')))
        results_table = test_data_results._generate_db_entries(test_data_results)

Now the funny part. I found that on subsequent calls to the API, the test_data_results kept on multiplying 😮 like the data from the previous POST also got appended to the current JSON which-should-be-processed. Thinking it was a problem with the client, I tried switching to curl, but with little luck.

The problem
Finally pycharm got me figuring out what went wrong, as it showed a warning on the test_table = [] something like:
The default method argument is mutable. Bah, taking at look at I see that when an empty list [] is kept as a default formal argument for a function, the list is not killed in between, and keeps on growing on subsequent calls – surprise :\

Quoting, when we have something like:

def status(options=[]):
    return options

print status()
print status()
print status()

will print something like

['new_option', 'new_option']
['new_option', 'new_option', 'new_option']

Tough luck finding it out, but it took couple of hours 😀 I got my code easily fixed by not allowing [] to stay as a default param, but separately passing an empty list to the function during the call. Like

class BenchmarkResults(object):

    def _generate_db_entries_helper(cls, tests, skip_aggregated=False, parent=None):
        test_table = []
        self._generate_db_entries(cls, tests, test_tables skip_aggregated=False, parent=None):

    def _generate_db_entries(cls, tests, test_table, skip_aggregated=False, parent=None):
         # This function recursively calls _generate_db_entries with test_table param set to a list 

Yay. that was it, and latter called in the helper function, and things started working. You can see the change here, and finally, Happy New year 2017! Make every commit count!

[Angular JS] Setting a combobox based on selection of another one

This might be my first post which touch Angular JS, and wanted to let you guys know that I too joined the backend to frontend club! Currently Angular JS is powering with Django REST at the backend – and I think its super fast, easy to develop and allows for a cleam responsive UI – WOW is the word.

You have a data model, which looks something like:

bots = [{ 'bot1' : {'platform': "Linux", id:1}}, { 'bot2' : {'platform': "Windows", id:2}}];
platforms = [{ 'name' :'Linux', 'id' :1},{ 'name' :'Windows', 'id' :2}, { 'name' :'MacOSuX', 'id' :3}];     

You have a select box bots and another select box Platforms and you need the following logic to happen:

  1. When no bot is selected,the Platforms combo should show All all the platform options
  2. When a bot is selected, it should force the Platform combo to show the platform property of bot selected, and should disable them to make no further changes.

You will need the following Angular script to make this work. Add this to your scripts.js or wherever place and include it in your html file.

app.controller('AppController', function($scope) {
    $scope.bots = [{ 'name': 'bot1', 'platform': "Linux", id:1}, { 'name': 'bot2', 'platform': "Windows", id:2}];
    $scope.platforms = [{ 'name' :'Linux', 'id' :1},{ 'name' :'Windows', 'id' :2}, { 'name' :'MacOSuX', 'id' :3}];     

see that you can even add this directly to the html file with the tag. Now you can add the following to the HTML file so that the data gets correctly rendered to the browser.

<div class="form-group">
  <label for="bot">Bot</label>
  <select name="bot" class="form-control" ng-model="selectedBot"
	  ng-options=" for bot in bots">
      <option value="">--All bots--</option>
<div class="form-group">
  <label for="platform">Platform</label>
  <select name="platform" class="form-control" ng-model="selectedPlatform" ng-disabled="selectedBot">
      <option value="">--All platforms--</option>
      <option ng-repeat="x in platforms" value="{{ }}">{{ }}</option>
      <option value="{{ selectedBot.platform }}" ng-selected="selectedBot" ng-show="selectedBot">
	  {{ selectedBot.platform }}</option>

How it works?

  • The {{ }} makes sure that all the platforms are shown initially making sure our condition (1) above.
  • The {{ selectedBot.platform }} makes sure that when the bot select is clicked, this option value is set for the combo box – adding to (2) above.
  • The ng-selected="selectedBot" ng-show="selectedBot" makes sure that the combo gets disabled when someone selects in some value for bots contributing to (2) above
  • You can see the dropdowns live in action at and do take a look and comment if something seems weird.

    Update: It seems like there was a problem with this approach as the selectedPlatform is not getting set correctly, even though the combo gets set. You can fix this by
    adding in the following action on ng-change on the select combo

    <select name="bot" class="form-control" ng-model="selectedBot"
          ng-options=" for bot in bots" ng-change="updateOtherCombos()">
      <option value="">--All bots--</option>

    and now defining the function updateOtherCombos() to your controllers.js

    app.controller('AppController', function($scope) {
        $scope.bots = [{ 'name': 'bot1', 'platform': "Linux", id:1}, { 'name': 'bot2', 'platform': "Windows", id:2}];
        $scope.platforms = [{ 'name' :'Linux', 'id' :1},{ 'name' :'Windows', 'id' :2}, { 'name' :'MacOSuX', 'id' :3}];     
        $scope.updateOtherCombos = function () {
          if ( $scope.selectedBot ) {
    	  $scope.selectedPlatform = $scope.selectedBot.platform;
    	  $scope.selectedCPU = $scope.selectedBot.cpu;
    	  $scope.selectedGPU = $scope.selectedBot.gpu;