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.
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
.
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.
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.
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.
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.
We then need to register the services as actions in the registerImageActions
function and append them to itemActions
.
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 service
, horizon.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.
We then write a function that will make a POST request and trigger the deactivation action for a specific image.
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.
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
The second: https://github.com/openstack/horizon/blob/master/openstack_dashboard/api/rest/glance.py
Deactivating an image should work now, and the status should be updated too.
The reactivate
code is quite similar to the deactivate code, so I won’t delve into it in detail.