Tabs in Dashboards

Hey everyone!! πŸ™‚

In one of my previous posts, I had explained some of the basics of working with dashboards in Horizon. In the past few weeks, I’ve learned a lot more about Horizon’s dashboards like creating tabs, workflows etc. In this post, I will share the basics of creating and working with Tabs.

When creating tabs, the most fundamental element is the TabGroup, which contains all your tabs. A TabGroup can contain one or more tabs, and can be defined for a panel in the file. A TabGroup is basically a container for individual Tabs. A basic TabGroup can be defined as follows:

class MyTabGroup(tabs.TabGroup):
    slug = "mypanel_tabs"
    tabs = (MyTab,)
    sticky = True

In the above code, MyTabGroup is the name for the TabGroup that you want to define (it can be named anything you want). The tabs attribute lists all the tabs that come under this TabGroup (in this case, just one tab called MyTab). There are a number of other attributes and methods that are available when working with TabGroups which you can find here.

Once you have defined a TabGroup, the next thing to be defined is the Tab itself. There are 2 types of Tabs that Horizon allows: Tab and TableTab. The Tab class allows you to create a simple tab, while the TableTab allows you to create a tab that knows how to handle any DataTables that are rendered inside it. The TableTab basically simplifies the complex handling of Tabs, their dynamic loading, Tables, their dynamic updating and the actions associated with them.

When creating an object of the Tab class, there are 3 attributes and methods must be given i.e. they are required. These are name, slug and get_context_data. The name attribute specifies the name that will be displayed in the HTML i.e. it is the display name for the tab. The slug attribute defines the URL slug and id for the Tab, and must thus be unique within a TabGroup. The get_context_data method returns the dictionary of the data that is to be used to render the Tab. A simple Tab can be defined as follows:

class MyTab(tabs.Tab):
    name = _("My Tab")
    slug = "my_tab"

    def get_context_data(self, request):
        app_id = self.tab_group.kwargs['application_id']
        solum = solumclient(request)
        app = solum.apps.find(name_or_id=app_id)
        return {"application": app}

In the above code, you can change the class name, the name attribute value and the slug attribute value to whatever you want. In the get_context_data method, you just need to ensure that you return a dictionary which contains all the data that you want to render using this Tab. The Tab class has a lot more attributes and methods that you can use to customize the Tab, more details about which you can find here.

There are also a few specific views that can be used to handle TabGroups like the TabView and the TabbedTableView. These classes have only one attribute that must always be defined, which is the tab_group_class attribute. The TabbedTableView simplifies handling both Tabs and Tables together. More details about the attributes and methods allowed for the TabView and the TabbedTableView can be found here.

In this post, I have covered just the basics of working with Tabs. But there is a lot more that can be done with Tabs. Horizon provides a lot of great functionalities and ways to customize Tabs.

Stay tuned for more updates regarding Horizon and some more cool features that it provides! πŸ˜€

Working with Horizon

Hey everyone! πŸ™‚

As I mentioned in my last post, I have been working with Solum’s dashboard and have been learning a lot about working with Horizon in this process. In my last post I described the basic dashboard structure for Horizon. In this post I’d like to share a few more details about working with Horizon as well as its dashboards.

I have been using a devstack setup with Solum also set up on it to test my work. In order to test the changes I make to the Solum dashboard, I make the relevant changes in the /opt/stack/solum-dashboard directory.

If you wish to create a custom dashboard from scratch and test it out on Horizon, Horizon provides a way of creating a dashboard directory with the structure required, which you can then customize. The steps that you can follow to create this directory structure are as follows:

mkdir openstack_dashboard/dashboards/mydashboard

./ -m startdash mydashboard --target openstack_dashboard/dashboards/mydashboard

./ -m startpanel mypanel --dashboard=openstack_dashboard.dashboards.mydashboard --target=openstack_dashboard/dashboards/mydashboard/mypanel

The above commands need to be run in the horizon directory itself i.e. the one where the script resides. The above commands generate the mydashboard directory with all the necessary files related to the dashboard, and the mypanel directory inside it with all the necessary files related to the panel. You can replace mydashboard and mypanel in the above commands with the names for the dashboard and panel as you wish. Once these directory structures are in place, you can start customizing the directory and panel as you wish.

In order to test any changes you make in a dashboard or even in the Horizon code itself, the Horizon server needs to be restarted to reflect the changes made, for which just restarting the Apache server suffices, the command for which is:

sudo service apache2 restart

Another very important thing to learn is how to debug the code you have written. So when working with Horizon, the error logs for Horizon are available in the /var/log/apache2/ directory, along with Horizon access logs, keystone access logs etc. In order to debug any error that you encounter when testing changes in a dashboard, whether it is an internal server error, or an error being thrown when trying to submit a form, further details about why the error is being thrown i.e. the relevant logs can be found in the horizon_error.log file.

Stay tuned for more updates on working with dashboards in Horizon! πŸ™‚

Working with Horizon Dashboards

Hey everyone!!

In my last post, I mentioned that I was working on getting Solum Horizon plugin working again. During the time that I have been working on this project, I have learned a few things about Horizon, its dashboards and their panels which I would like to share with you guys.

Firstly, what is Horizon? Horizon is basically just the implementation of the OpenStack Dashboard which allows you to access OpenStack services such as Nova, Glance, Swift etc through a web interface.

In order to access Solum’s dashboard in the Horizon interface, it needs to be manually loaded into the horizon setup you have (to know more about how to manually load Solum into your Horizon server, check this out, or to setup a devstack environment with Solum running on it, look here).

My work till this now involved setting up a new panel for languagepacks in the already existing Solum dashboard plugin.

The very first thing that needs to be done when creating a new panel is adding it to the panels attribute of the file in the plugin. After that, you need to create a new directory for your panel, which will contain all your python files (most of the backend) for your panel. The files that come in the directory for your panel are:

This file is the one that is used to discover the code for the corresponding panel for a panel listed in the panels attribute of the dashboard.

Horizon simplifies the majority of displaying data to the user. It provides the options of using tables (the different types it provides and their attributes and methods are listed here). Within a table definition, there is also the option of adding row_actions and table_actions. When creating an action for a table (whether it be a row action or a table action), it is important to create a class for it within the file. Now this class that you create can inherit from the LinkAction table of horizon (or one of the other action types provided in Horizon as listed here).

All of the code that has been written so far is tied together in a view through the file. Here too, Horizon provides a few different views that can be used (the simplest ones related to tables are listed here).

This files lists the urls for the different views you have created.

Now, in the templates folder of the dashboard, we need to create a directory corresponding to our panel. All the html files corresponding to your panel go into this folder. With this, you can create a pretty basic panel in Horizon πŸ˜€ (for more details about the code, you can look here).

This post just scratches the surface of what can be done in a dashboard for Horizon. Stay tuned for more updates regarding horizon and some of the other cool stuff that can be done in a dashboard! πŸ™‚


Summer Internship at OpenStack! :)

Hey everyone!

I have been accepted as an Outreachy intern for OpenStack for the summer and will be working on Solum under my mentor Devdatta Kulkarni.

My project is to get the Solum Horizon plugin working again. In its current state, the plugin is not in working condition. My job is to make changes in its code to make it compatible with Solum’s current APIs for applications and languagepacks.

At the halfway point for the internship, I have implemented the changes in the plugin code to support the list, show and delete functionalities for languagepacks. I have also started working on the supporting the creation of languagepacks through the dashboard.

I had first looked through the horizon documentation for creating a new panel for languagepacks. Β Then in order to implement the CRUD options, I had to go through the already existing code in the plugin for applications, and also took a look at the code for some of the other dashboards (like that of murano) to get an idea of how to go about implementing these options. In this whole process, I learned a bit about how Django works.

Further, to implement these options, I took a look at how to establish a connection to the solumclient from the plugin and then use that connection to carry out the task. In order to do this, I went through the code for the client from the python-solumclient module and learned about how the client connection is established and how this client is used to carry out the different CRUD commands.

My next step would be to complete the implementation of creation of languagepacks.

I’ll continue sharing updates about my internship. So stay tuned! πŸ™‚

My Journey through OpenStack!

I am currently doing my Bachelor of Technology in Computer Science (third year) from International Institute of Information Technology, Hyderabad. I am applying for the Outreachy round 11 in OpenStack.

I came across Outreachy a while ago, and decided to take part in it as I am passionate about coding and learning about new technologies, and Outreachy seemed like a perfect platform to learn and grow.

A close friend of mine, Itisha Dewan, introduced me to OpenStack. I looked through all the projects, and picked the one that I found most interesting, which was Solum. Solum is the Software Development Lifecycle Automation service for OpenStack. I contacted the potential mentor for the project, Devdatta Kulkarni (IRC nick devkulkarni on Freenode) on IRC, and he helped me alot in getting started. He was extremely patient and helped me in figuring things out from scratch. He gave me my first bug, a low-hanging-fruit (the link to it) which I managed to solve, and gained a little confidence from. I subsequently understood more about Solum from him and other members of Solum, who were all extremely helpful and supportive. I moved on to solve a few other bugs suggested to me by Dev, and also discussed the various proposed projects in Solum for Outreachy with him.

The OpenStack community has been extremely helpful and supportive, especially my mentor Dev who has been extremely patient with me and has been a major source of motivation for me. I am really glad I decided to contribute to OpenStack and Solum, which has such an experienced community that I could learn a lot from. I hope I get selected for Outreachy so that I can contribute further to OpenStack and learn as much as I can from the internship.

Thanks for reading! πŸ™‚