Ever wondered how complex features get built in massive open-source projects? Follow the detailed path of implementing image deactivation in OpenStack Horizon.

image

Getting your first feature merged into a big open-source project is exciting. In this guide, I’ll be focusing on how I implemented the deactivate/reactivate feature on OpenStack Horizon.

If you’re interested, I’ve written a deep dive into the thought process and behind-the-scenes details.

For now, let’s get coding.

The front end

The deactivate/reactivate feature was going to be one of the options available when you clicked the drop-down next to the Launch button on the OpenStack Horizon dashboard.

OpenStack Horizon Image Options

Deactivate is one of the statuses that an image can have. The Glance docs include an image to illustrate the various transitions an image can undergo.

Once you deactivate an image, you can reactivate it, changing its status back to Active.

Image transition statuses

When you deactivate an image, you can no longer use its data.

I began by writing the front-end code that would ultimately allow us to have deactivate as one of the actions that you can take on an image.

OpenStack Horizon Image Options with Deactivate

Identifying the directory I was going to be working with

First, I identified the directory I was going to be working with.

https://github.com/openstack/horizon/tree/master/openstack_dashboard/static/app/core/images

The images directory contained Glance code on Horizon.

The aforementioned drop-down next to Launch lists the various options to choose from when working with an image in Horizon.

I noticed that the steps directory contained most of those options (create-image, create-volume, edit-image, and update-metadata).

https://github.com/openstack/horizon/tree/master/openstack_dashboard/static/app/core/images/steps

And each option had its own directory, containing at least a controller and a view.

Writing the view and controller

I went to work writing the code for the view and controller. Note that the code is an Immediately Invoked Function Expression (IIFE). The code base uses AngularJS, which uses ES5 JavaScript.

Controller code snippet

At this point, you still cannot see the controller and view code on the front end. Since deactivate and reactivate are actions that you take on an image, you need to add some code to the actions directory.

https://github.com/openstack/horizon/tree/master/openstack_dashboard/static/app/core/images/actions

Services and modules

AngularJS services help you organize and share code across your app. You add the code you need shared as dependencies.

AngularJS modules are, in essence, containers for different parts of your app. They can include controllers, views, and services.

To see the front-end code we wrote (controllers and views), we need to create some services and add them as dependencies to our module.

I created two services, the deactivate-image service and the reactivate-image service.

Deactivate image service code snippet

Services also need code from other parts of the code base. We add these dependencies via deactivateImageService.$inject.

After creating our services, we need to add them to the actions module.

https://github.com/openstack/horizon/blob/master/openstack_dashboard/static/app/core/images/actions/actions.module.js

First, we add the services as dependencies via registerImageActions.$inject.

Actions module code snippet

We then need to register the services as actions in the registerImageActions function and append them to itemActions.

Actions module code snippet

itemActions are operations that you can perform on a specific image, for example, editing an image or updating its metadata.

The front end this far

At this point, our front-end code is good to go. Deactivate is one of the options on the drop-down next to Launch.

A modal also pops up when we click deactivate.

I imported the modal as a dependency in the deactivate-image servicehorizon.framework.widgets.modal.simple-modal.service.

The modal template is defined at https://github.com/openstack/horizon/blob/master/horizon/static/framework/widgets/modal/simple-modal.service.js

You’ll find a lot of the templates for the dependencies you need in the https://github.com/openstack/horizon/blob/master/horizon/static directory.

At this point, even if you deactivate the image, its status doesn’t get updated. We haven’t written the back-end functionality yet.

The back end

The first part of the back-end code involves making an API call to Glance. We need to access the https://github.com/openstack/horizon/blob/master/openstack_dashboard/static/app/core/openstack-service-api/glance.service.js file and add some code there.

We start by adding the deactivate method to the glanceAPI factory. A factory is a function that returns objects that are reused by services and controllers.

Adding the deactivate method to the glanceAPI factory

We then write a function that will make a POST request and trigger the deactivation action for a specific image.

The deactivate image function

Currently, when you attempt to deactivate the image on the front end, the table does not update its status. The pop-up also displays two contradictory messages, indicating a bug.

The deactivate image function

This is because tables on the Horizon interface are actually displayed by Django, and thus far, we have only written AngularJS code.

We’ll need to add some code to two files. The first: https://github.com/openstack/horizon/blob/master/openstack_dashboard/api/glance.py

Deactivate image code

The second: https://github.com/openstack/horizon/blob/master/openstack_dashboard/api/rest/glance.py

Deactivate image code

Deactivating an image should work now, and the status should be updated too.

Successfully deactivated image

The reactivate code is quite similar to the deactivate code, so I won’t delve into it in detail.

Next steps

 With the deactivate/reactivate feature ready, it’s now time for the next challenge—testing.