UI Extensions

Every organization has some unique requirements, tools, and processes that may not be addressed by the stock CloudBolt application. For this reason, you have the ability to extend the user interface through UI extensions.

To get started, check out samples of UI extentions available from the CloudBolt Content Library. Visit Admin > UI Extensions Management and click on the “Cloud download” button at the top right.

Note

Creating and maintaining UI extensions is an advanced endeavor that may impose a cost. Because you are working with internal APIs rather than public ones, things are more likely to evolve over time. You may need to test and upgrade your extensions when upgrading CloudBolt.

If you need help implementing a UI extension, please contact CloudBolt Software for support or to start a professional services engagement.

Writing an extension is similar to writing a CloudBolt Plugin orchestration actions. Your extension has access to all CloudBolt internal models and functions. In addition, it and can make use of 3rd party libraries so long as they’ve been installed on the Python path. It’s a good idea to confirm with CloudBolt Software before installing these to be sure there won’t be conflicts.

Extension developers need to be versed in Python and basic Django knowledge at a minimum, like views, urls and templates. They will likely need to use the interactive Django shell on the CB server to develop queries, introspect model instances, etc. This shell is also available from within the UI using the Jupyter Notebook feature (which is enabled in Admin > Miscellaneous Settings).

Package Structure

UI extensions are Python packages that include the following components.

network_topology_extensions/
    __init__.py              <-- Required, it's a Python thing
    views.py                 <-- Django views
    templates/               <-- Django templates
        chart.html           <-- used by the sample report view
        dashboard_card.html  <-- used by the sample dashboard card view
        server_tab.html      <-- used by the sample tab view
        settings.html        <-- used by the sample admin view
    urls.py                  <-- Django urls for custom methods define in sample views

One extension, or Python package, may register multiple extensions at various points throughout the UI.

To install an extension, zip the package using gzip and upload it on the management page.

UI Elements that Support Extensions

Dashboard Cards

The Dashboard view comes with a handful of standard sections, also referred to as cards. Define a new card by decorating the view function with dashboard_extension:

from extensions.views import dashboard_extension

@dashboard_extension(
    title='Network Topo Status',
    description='Optional description only shown on Admin > Manage UI Extensions'
)
def network_topo_dashboard_card(request):
    data = your_custom_logic_gets_network_topo_data()

    # Template path starts with the extension folder name.
    return render(request, 'network_topology_extensions/templates/dashboard_card.html', dict(
        data=data,
    ))

Reports

You can add a custom report by using the report_extension decorator.

from extensions.views import report_extension

@report_extension(
    title='Network Topo Map', # what end users see under the Reports menu in the navbar
    description='Optional description shown in the Reports page and as tooltips in the menu',
    thumbnail='my_ext/thumbnail.png' # Optional, see docs below
)
def network_topo_map_report(request):
    """
    Check out the report extensions in the content library. Reports may incorporate tables as
    well as charts using the built-in Highcharts JavaScript library.
    """
    networks = ResourceNetwork.objects.all()
    my_data = [0, 1, 2, 3, 4]
    return render(request, 'network_topology_extensions/templates/chart.html', dict(
        networks=networks,
    ))

To define your own custom thumbnail image for a report extension (shown in the menu bar and on the Reports landing page), do the steps below in Front End Assets and Tools and then add a thumbnail kwarg to the decorator with the relative path to the image starting from the extensions folder: @report_extension(title=’…’, thumbnail=’my_ext/pie_chart.png’)

Detail View Tabs

Extensions may register new tabs for the following models’ detail view: Group, Environment, Server, Resource, Blueprint, and Resource Handler. Use the tab_extension decorator.

from extensions.views import tab_extension
from infrastructure.models import Server

@tab_extension(
    title='Network Topo Map',  # `title` is what end users see on the tab
    description='Optional description only shown on Admin > Manage UI Extensions',
    model=Server, # Required: the model this extension is for
)
def server_network_topo_map_tab(request, obj_id):
    """
    Check out the report extensions in the content library. Reports may incorporate tables as
    well as charts using the built-in Highcharts JavaScript library.

    Tab extension view functions receive an additional arg, `obj_id`, which is the ID of the
    model instance whose detail view this tab appears on. In this case, a Server ID.
    """
    # Instantiate the server instance using the ID passed in.
    server = Server.objects.get(id=obj_id)

    return render(request, 'network_topology_extensions/templates/server_tab.html', dict(
        server=server,
    ))

Admin Pages

Add custom admin pages to the Admin > UI Extensions.

from extensions.views import admin_extension

@admin_extension(
    title='Network Topo Map Settings',
    description='Optional description becomes a tooltip on the Admin page',
)
def network_topo_map_settings(request):
    """
    Check out the report extensions in the content library. Reports may incorporate tables as
    well as charts using the built-in Highcharts JavaScript library.
    """
    return render(request, 'network_topology_extensions/templates/settings.html', dict(
    ))

Special Considerations with Custom URLs

If an extension includes, buttons, links, or a dialog that needs to refer back to a custom view, it will include a urls.py. There are some special considerations to be aware of in these cases.

Custom URLs should be declared using the xui_urlpatterns variable instead of the familiar urlpatterns used in Django apps.

from django.conf.urls import url
from xui.sample import views

xui_urlpatterns = [
    url(r'^a-sample-url-with-obj-id/(?P<obj_id>\d+)/$', views.sample_method_1,
        name='sample_method_1'),
    url(r'^some-other-sample-url/$', views.sample_method_2, name='sample_method_2')
]

When referencing your custom URLs in a template use the relative path instead of the url Django template tag.

{# sample template #}

<a href="/a-sample-url-with-obj-id/{{ obj.id }}/">Call method 1</a>

<a href="/some-other-sample-url/">Call method 2</a>

Access Control

See samples in the Content Library for how to implement fine-grained access to extensions via the delegate keyword arg on the decorator function. This is available to all extension types and enables you to hide or show the extension based on the user’s group, roles, permissions, and so forth.

Troubleshooting

Watch the application log when developing and troubleshooting extensions.

tail -f /var/log/cloudbolt/application.log

Reload the page and check for Python errors in that live stream. You may need to restart the web server to see your Python changes: service httpd restart.

Front End Assets and Tools

For extensions that require advanced interactivity, visualizations, or other client side scripting, the following libraries are available:

Custom images and other static assets required by an extension should be bundled with it for portability and maintenance reasons. A little extra work is required to make these available through the CloudBolt web server.

# Create a folder for extension assets on your CB server, if one does not
# exist yet.
mkdir /var/opt/cloudbolt/proserv/static/uploads/extensions

# We recommend you create a folder for each UI extension requiring static
# assets, as well as a folder for common assets used by more than one
# extension.
mkdir /var/opt/cloudbolt/proserv/static/uploads/extensions/your_ext_name

# Copy JavaScript/CSS/image files into this folder...

# Run `collectstatic` to make assets available from the CB web server
/opt/cloudbolt/manage.py collectstatic --noinput

If you’ve done the above for a file named /var/opt/cloudbolt/proserv/static/uploads/extensions/hadoop/vis.js, your code can reference it in the page like this: <script src=”/static-HASH/uploads/extensions/hadoop/vis.js” />. The “HASH” value can be any string; it’s a standard technique to force browsers and proxies to load a new copy of your script and forget about previously cached ones.