Installation from RPM repository

To install NodeConductor standalone on RHEL7-compatible operating systems (CentOS 7, Scientific Linux 7):

# Configure repositories
yum -y install epel-release
yum -y install

# Set up PostgreSQL
yum -y install
yum -y install postgresql95-server
/usr/pgsql-9.5/bin/postgresql95-setup initdb
systemctl start postgresql-9.5
systemctl enable postgresql-9.5

su - postgres -c "/usr/pgsql-9.5/bin/createdb -EUTF8 nodeconductor"
su - postgres -c "/usr/pgsql-9.5/bin/createuser nodeconductor"

# Set up Redis
yum -y install redis
systemctl start redis
systemctl enable redis

# Set up NodeConductor
yum -y install nodeconductor

su - nodeconductor -c "nodeconductor migrate --noinput"

systemctl start nodeconductor-uwsgi
systemctl enable nodeconductor-uwsgi

systemctl start nodeconductor-celery
systemctl enable nodeconductor-celery

systemctl start nodeconductor-celerybeat
systemctl enable nodeconductor-celerybeat

All done. NodeConductor API should be available at http://myserver/api/ (port 80).

Note that database server (PostgreSQL) and key-value store (Redis) may run on a separate servers – in this case modify installation process accordingly.

For plugin installation instructions see NodeConductor’s plugin section.


NodeConductor configuration file can be found at /etc/nodeconductor/settings.ini.

Installation from source

Additional requirements:

  • git
  • redis and hiredis library
  • virtualenv
  • C compiler and development libraries needed to build dependencies
    • CentOS: gcc libffi-devel openssl-devel python-devel
    • Ubuntu: gcc libffi-dev libsasl2-dev libssl-dev python-dev

NodeConductor installation

  1. Get the code:
git clone
  1. Create a Virtualenv and update Setuptools:
cd nodeconductor
virtualenv venv
venv/bin/pip install --upgrade setuptools
  1. Install NodeConductor in development mode along with dependencies:
venv/bin/python develop
  1. Create and edit settings file (see ‘Configuration’ section for details):
cp nodeconductor/server/ nodeconductor/server/
vi nodeconductor/server/
  1. Initialise database – SQLite3 database will be created in ./db.sqlite3 unless specified otherwise in settings files:
venv/bin/nodeconductor migrate --noinput
  1. Collect static data – static files will be copied to ./static/ in the same directory:
venv/bin/nodeconductor collectstatic --noinput
  1. Start NodeConductor:
venv/bin/nodeconductor runserver


NodeConductor is a Django based application, so configuration is done by modifying

If you want to configure options related to Django, such as tune caches, configure custom logging, etc, please refer to Django documentation.

Configuration for NodeConductor is namespaced inside a single Django setting, named NODECONDUCTOR.

Therefore configuration might look like this:

    'CLOSED_ALERTS_LIFETIME': timedelta(weeks=1),
        'username': 'username',
        'password': 'password',
        'host': '',
        'port': '9999',
        'protocol': 'https',
    'ENABLE_GEOIP': True,
    'GOOGLE_API': {
        'Android': {
            'server_key': 'AIzaSyA2_7UaVIxXfKeFvxTjQNZbrzkXG9OTCkg',
        'iOS': {
            'server_key': 'AIzaSyA34zlG_y5uHOe2FmcJKwfk2vG-3RW05vk',
    'SHOW_ALL_USERS': False,
    'TOKEN_KEY': 'x-auth-token',
    'TOKEN_LIFETIME': timedelta(hours=1),

Available settings

Specifies closed alerts lifetime (timedelta value, for example timedelta(hours=1)). Expired closed alerts will be removed during the cleanup.

Dictionary of Elasticsearch parameters.

Elasticsearch host (string).
Elasticsearch port (integer).
Elasticsearch server access protocol (string).
Username for accessing Elasticsearch server (string).
Password for accessing Elasticsearch server (string).
Enables verification of Elasticsearch server TLS certificates (boolean).
Path to the TLS certificate bundle (string).
Indicates whether geolocation is enabled (boolean).
Defines whether extensions should be automatically registered (boolean).

Settings dictionary for Google Cloud Messaging.


Settings for Android devices.

Google Cloud messaging server key.

Settings for IOS devices.

Google Cloud messaging server key.
String to be displayed in the notification pop-up title.
Seller legal or effective country of registration or residence as an ISO 3166-1 alpha-2 country code. It is used for computing VAT charge rate.
Indicates whether user can see all other users in api/users/ endpoint (boolean).
If it is set to True, then only customers with positive balance will be able to modify entities such as services and resources (boolean).
Indicates whether user can manage owned customers (boolean).
Header for token authentication. For example, ‘x-auth-token’.
Specifies authentication token lifetime (timedelta value, for example timedelta(hours=1)).

NodeConductor will send notifications from email address specified in DEFAULT_FROM_EMAIL variable. For example,


See also: Django database settings.

Shareable services

NodeConductor is designed to support multiple API-based services for access sharing. Services can range from IaaS to SaaS, the common denominator is the ability to control services over APIs. Currently supported services are listed below.

Backend Provision Import Destroy Manage Monitor Backup
Amazon *
Azure * VirtualMachine yes yes restart
DigitalOcean * VirtualMachine yes yes start/stop/restart
GitLab * Group, Project yes yes
JIRA * yes
OpenStack * VirtualMachine yes yes start/stop/restart/resize zabbix snapshots
Oracle * Database start/stop/restart
SugarCRM * CRM yes user CRUD

* available via NodeConductor extensions

Background processing

For executing heavier requests and performing background tasks NodeConductor is using Celery. Celery is a task queue that supports multiple backends for storing the tasks and results. Currently NodeConductor is relying on Redis backend - Redis server must be running for requests triggering background scheduling to succeed.

If you are developing on OS X and have brew installed:

brew install redis-server

Please see Redis docs for installation on other platforms.

Error state of background tasks

If a background task has failed to achieve it’s goal, it should transit into an error state. To propagate more information to the user each model with an FSM field should include a field for error message information - error_message. The field should be exposed via REST. Background task should update this field before transiting into an erred state.

Cleaning of the error state of the model instance should clean up also error_message field.

State machines

Some of the models in NodeConductor have a state field representing their current condition. The state field is implemented as a finite state machine. Both user requests and background tasks can trigger state transition. A REST client can observe changes to the model instance through polling the ‘state’ field of the object.


Let’s take VM instance in ‘offline’ state. A user can request the instance to start by issuing a corresponding request over REST. This will schedule a task in Celery and transition instance status to ‘starting_scheduled’. Further user requests for starting an instance will get state transition validation error. Once the background worker starts processing the queued task, it updates the Instance status to the ‘starting’. On task successful completion, the state is transitioned to ‘online’ by the background task.

Customers, Projects, Services, Resources and Users

NodeConductor is a service for sharing resources across projects. It is based on the delegation model where a customer can allocate certain users to perform technical or non-technical actions in the projects.


An account in NodeConductor belonging to a person or a robot. A user can belong to groups that can grant him different roles.
A standalone entity. Represents a company or a department.
Customer owner
A role of the user that allows her to represent a corresponding customer. In this role, a user can create new projects, register resources, as well as allocate them to the projects.
Service settings
Represents an account of particular cloud service, for example, AWS, OpenStack, GitHub or Oracle. Account credentials must provide full access to service API. It is possible to mark service settings as “shared” and they will be automatically connected to all customers (service that is “available for all” will be created as connection between service settings and customer).
A standalone entity. Represents cloud service within NodeConductor and belongs to a customer. Customer can have any number of any services. If service is “available_for_all” - it will be automatically connected to each customer project.
Connection between service and project.
Service property
Represents any properties of cloud service usually used for a resource provisioning. For example: image and flavor in OpenStack or zone and template in Oracle.
General service property
Represents any property of a service that is not connected to service settings.
A project is an entity within a customer. Project has a linked group of users collaborating on work - ‘project administrators’. Project aggregates and isolates resources. A customer owner can allow usage of certain clouds within a project - defining what resource pools project administrators can use.
Project administrator
A project role responsible for the day-to-day technical operations within a project. Limited access to project management and billing.
A resource is a provisioned entity of a service, for example, a VM in OpenStack or AWS, a repository in GitHub or a database in Oracle. Each resource belongs to a particular project.
Project group
Projects can be grouped together for convenience or permission delegation from Customer owner to Project group manager.
Project group manager
An optional non-technical role that a customer can use to delegate management of certain projects to selected users. Project group manager can create new projects and manage administrators within a scope of a certain project group.


Relationships between customers and services:

Example of shared settings and private service:
  • OpenStack service settings - shared settings, that are available for all customers.
  • Private Customer A service with separate settings - available only for customer A.

Groups and permissions

NodeConductor is using Django groups for permission management of the higher-level entities like Project or Customer. Membership in these groups defines if a user account has the corresponding role.

Event types

Following event types are emitted by NodeConductor.

User events

User authenticated successfully with username and password.
User failed to authenticate with username and password.
User authenticated successfully with Omani PKI.

User has been created.
User has been updated.
User has been deleted.

User has been activated.
User has been deactivated.

Password has been changed for user.

SSH key has been created.
SSH key has been deleted.

Structure events

Customer has been created.
Customer has been updated.
Customer has been deleted.

User has claimed organization.
User has been approved for organization.
User claim for organization has been rejected.
User has been removed from organization.

Project group has been created.
Project group has been updated.
Project group has been deleted.

Project has been created.
Project name has been updated.
Project has been updated.
Project has been deleted.
Project has been added to project group.
Project has been removed from project group.

User has gained role.
User has lost role.

Resource events are generic and contain a field resource_type that can be used for discriminating what has been affected. Possible values depend on the plugins enabled, for example OpenStack.Instance or SaltStack.ExchangeTenant.

Resource creation events. Emitted on creation of all events, i.e. both VMs and applications.
Resource update has been updated.
Resource deletion events.
Events for resources that can change state from online to offline, i.e. virtual machines.
Resource has been imported.

Template events

These events are only related to the ITACLOUD assembly.

Template has been created.
Template has been updated.
Template has been deleted.

Template service has been created.
Template service has been updated.
Template service has been deleted.

Invoicing events

Invoice has been created.
Invoice has been updated.
Invoice has been deleted.

Custom events

Event emitted by admin user.

Declaring resource actions

Any methods on the resource viewset decorated with @detail_route(methods=[‘post’]) will be recognized as resource actions. For example:

class InstanceViewSet(structure_views.BaseResourceViewSet):

    def start(self, request, resource, uuid=None):

    def unlink(self, request, resource, uuid=None):

Rendering simple actions

Given the previous example, the following metadata is rendered for actions as response to OPTIONS request against resource endpoint

    "actions": {
        "start": {
            "title": "Start",
            "url": "",
            "enabled": false,
            "reason": "Performing start operation is not allowed for resource in its current state",
            "destructive": false,
            "method": "POST"
        "unlink": {
            "title": "Unlink",
            "url": "",
            "enabled": true,
            "reason": null,
            "destructive": true,
            "type": "button",
            "method": "POST"

Simple actions, such as start and unlink, do not require any additional data. In order to apply it, you should issue POST request against endpoint specified in url field. Some actions, such as start and stop, may be undone, but unlink action can’t be. In order to indicate it, set destructive attribute on the viewset method. Usually such action is rendered on the frontend with warning indicator. If you do not want to use the default title generated for your action, set title attribute on the viewset method. If action is not enabled for resource it is rendered on the frontend with disabled class and reason is shown as tooltip.

Complex actions and serializers

If your action uses serializer to parse complex data, get_serializer_class method on the resource viewset should return action-specific serializer. For example:

class InstanceViewSet(structure_views.BaseResourceViewSet):

    serializers = {
        'assign_floating_ip': serializers.AssignFloatingIpSerializer,
        'resize': serializers.InstanceResizeSerializer,

    def get_serializer_class(self):
        serializer = self.serializers.get(self.action)
        return serializer or super(InstanceViewSet, self).get_serializer_class()

In this case action has form type and list of input fields is rendered. The following attributes are exposed for action’s fields: label, help_text, min_length, max_length, min_value, max_value, many. For example, given this serializer the following metadata is rendered:

class InstanceResizeSerializer(serializers.Serializer):
    disk_size = serializers.IntegerField(min_value=1, label='Disk size')

    def get_fields(self):
        fields = super(InstanceResizeSerializer, self).get_fields()
        if self.instance:
            fields['disk_size'].min_value = self.instance.data_volume_size
        return fields
    "actions": {
        "resize": {
            "title": "Resize virtual machine",
            "url": "",
            "fields": {
                "disk_size": {
                    "type": "integer",
                    "required": false,
                    "label": "Disk size",
                    "min_value": 1024
            "enabled": true,
            "reason": null,
            "destructive": false,
            "type": "form",
            "method": "POST"

Filtering valid choices for action’s fields

Frontend uses list of fields supported by action in order to render dialog. For fields with select type, url attribute specifies endpoint for fetching valid choices. Choices are not rendered for performance reasons, think of huge list of choices. Each object rendered by this endpoint should have attributes corresponding to value of value_field and display_name_field. They are used to render select choices.

In order to display only valid field choices to user in action’s dialog, ensure that serializer’s field has the following attributes: view_name, query_params, value_field and display_name_field. For example:

class AssignFloatingIpSerializer(serializers.Serializer):
    floating_ip = serializers.HyperlinkedRelatedField(
        label='Floating IP',

    def get_fields(self):
        fields = super(AssignFloatingIpSerializer, self).get_fields()
        if self.instance:
            query_params = {
                'status': 'DOWN',
                'project': self.instance.service_project_link.project.uuid,
                'service': self.instance.service_project_link.service.uuid

            field = fields['floating_ip']
            field.query_params = query_params
            field.value_field = 'url'
            field.display_name_field = 'address'
        return fields

Given previous serializer the following metadata is rendered:

    "actions": {
        "assign_floating_ip": {
            "title": "Assign floating IP",
            "url": "",
            "fields": {
                "floating_ip": {
                    "type": "select",
                    "required": true,
                    "label": "Floating IP",
                    "url": "",
                    "value_field": "url",
                    "display_name_field": "address"
            "enabled": true,
            "reason": null,
            "destructive": false,
            "type": "form",
            "method": "POST"


NodeConductor uses token-based authentication for REST.

In order to authenticate your requests first obtain token from any of the supported token backends. Then use the token in all the subsequent requests putting it into Authorization header:

GET /api/projects/ HTTP/1.1
Accept: application/json
Authorization: Token c84d653b9ec92c6cbac41c706593e66f567a7fa4

Also token can be put as request GET parameter, with key x-auth-token:

GET /api/?x-auth-token=Token%20144325be6f45e1cb1a4e2016c4673edaa44fe986 HTTP/1.1
Accept: application/json

Every NodeConductor REST request supports pagination. Links to the next, previous, first and last pages are included in the Link header. X-Result-Count contains a count of all entries in the response set.

By default page size is set to 10. Page size can be modified by passing ?page_size=N query parameter. The maximum page size is 100.

Example of the header output for user listing:

HTTP/1.0 200 OK
Vary: Accept
Content-Type: application/json
 <>; rel="first",
 <>; rel="next",
 <>; rel="prev",
 <>; rel="last"
X-Result-Count: 54

Listing permissions

Entities of NodeConductor are grouped into organisational units. The following organisational units are supported: customer, project group and project.

Each organisational unit has a list of users associated with it. Getting a list of users connected to a certain organisational unit is done through running a GET request against a corresponding endpoint.

  • customer: endpoint /api/customer-permissions/
  • project_group: endpoint /api/project-group-permissions/
  • project: endpoint /api/project-permissions/

Filtering by organisational unit UUID or URL is supported. Depending on the type, filter field is one of:

  • ?customer=<UUID>
  • ?customer_url=<URL>
  • ?project_group=<UUID>
  • ?project_group_url=<URL>
  • ?project=<UUID>
  • ?project_url=<URL>
  • ?user_url=<URL>

In addition, filtering by field names is supported. In all cases filtering is based on case insensitive partial matching.

  • ?username=<username>
  • ?full_name=<full name>
  • ?native_name=<native name>

Ordering can be done by setting an ordering field with ?o=<field_name>. For descending ordering prefix field name with a dash (-). Supported field names are:

  • ?o=user__username
  • ?o=user__full_name
  • ?o=user__native_name

Import OpenStack instance

To import OpenStack instance - execute “importopenstackinstance” management command.

OpenStack, KillBill and Zabbix plugins should be installed for a successful command execution.

Monitoring-as-a-service (MaaS)

NodeConductor can be used for implementing a MaaS solution for OpenStack VMs with Zabbix monitoring service.

Two approaches for MaaS are available:

1. A pre-packaged Zabbix appliance deployed into defined OpenStack tenant for the highest flexibility.

2. A pre-packaged Zabbix appliance configurable by NodeConductor after the deployment of the appliance (“Advanced monitoring”). Intended for use cases when OpenStack hosts need to be registered manually or automatically in the monitoring server deployed in a tenant.

Below we describe configuration approach for both of the cases.

Zabbix appliance only


  1. Create a template group:
  • name, description, icon_url - support parameters for the application store
  • tags - PaaS
  1. Add OpenStack Instance template to the template group with the following settings:
  • tags - PaaS, license-application:zabbix:Zabbix-3.0, license-os:centos7:CentOS-7-x86_64, support:premium
  • service settings - OpenStack settings where a VM needs to be provisioned
  • flavor - default configuration for the created Zabbix server
  • image - OpenStack image with pre-installed Zabbbix
  • data volume, system volume - default size for Zabbix deployments

Supported operations by REST client

Zabbix appliance is a basic OpenStack image that supports the following provisioning inputs:

  • name
  • project
  • security groups
  • user_data

User data can be used to setup Zabbix admin user password:

  - [ bootstrap, -a, <Zabbix admin user password> ]

Advanced monitoring

Provisioning flow

NodeConductor requires a separate template group for advanced monitoring that contains 2 templates:

  • OpenStack VM template - describing provision details of a new VM with Zabbix;
  • Zabbix service template - creating a Zabbix service, based on created VM details.


  1. Add settings for SMS sending to NodeConductor settings:
        'SMS_EMAIL_FROM': '',
        'SMS_EMAIL_RCPT': '{phone}',

See also: NodeConductor Zabbix plugin configuration.

  1. Add Zabbix security group to all existing tenants:
nodeconductor initsecuritygroups zabbix
nodeconductor initsecuritygroups zabbix-agent
  1. Create template group:
  • name, description, icon_url - support parameters for the application store
  • tags - SaaS
  1. Add OpenStack instance provision template:
  • tags - SaaS, license-application:zabbix:Zabbix-3.0, license-os:centos7:CentOS-7-x86_64, support:advanced
  • service settings - OpenStack settings where a VM needs to be provisioned
  • flavor - choose suitable for Zabbix image
  • image - OpenStack image with pre-installed Zabbbix
  • data volume, system volume - default size for Zabbix deployments
  • user data:
  - [ bootstrap, -a, {{ 8|random_password }}, -p, {{ 8|random_password }}, -l, "%", -u, nodeconductor ]

{{ 8|random_password }} will generate a random password with a length of 8
  1. Add Zabbix service provision template:
  • order_number - 2 (should be provisioned after OpenStack VM)
  • name - {{ }} (use VM name for service)
  • scope - {{ response.url }} (tell service that it is located on given VM)
  • use project of the previous object - True (connect service to VM project)
  • backend url - http://{{ response.access_url.0 }}/zabbix/api_jsonrpc.php (or https)
  • username - Admin
  • password - {{ response.user_data|bootstrap_opts:”a” }}
  • tags - advanced
  • database parameters:
     "engine": "django.db.backends.mysql",
     "name": "zabbix",
     "host": "XXX",
     "user": "nodeconductor",
     "password": "{{ response.user_data|bootstrap_opts:'p' }}",
     "port": "3306"

Parameter “host” should be specified based on environment and Zabbix image configuration.

Requests from frontend

  1. To create instance with advance monitoring issue POST request to template_group provision endpoint with project, name and security group named “zabbix”.

  2. To get list of all available for instance advanced zabbix services - issue GET request against /api/zabbix/ with parameters:

    • project=<instance project>
    • tag=advanced
  3. To create host for instance - issue POST request against /api/zabbix-hosts/ with instance url as scope. Check endpoint details for other parameters details.

  4. Instance advanced monitoring can be enabled/disabled by changing host status with PUT/PATCH request against /api/zabbix-hosts/<uuid>/.

  5. If instance is already monitored - host will appear in <related_resources> with tag “advanced” in service_tags field.

  6. Instance advanced monitoring can be configured with PUT/PATCH request against /api/zabbix-hosts/<uuid>/.

Disaster recovery backups (DR backup)

DR backups allow storing backups of instances outside of an OpenStack deployment and restoring it on other deployment.

How it works

On DR backup creation NodeConductor creates cinder backups for each volume of the instance, stores instance metadata and exports and saves metadata records of cinder backups.

On DR backup restoration NodeConductor creates cinder backups in a new tenant, based on saved metadata records. After that it creates new volumes and restores cinder backups into them. Finally, NodeConductor creates new instance based on restored volumes and backup metadata.

API calls

To create new DR backup, issue POST request with instance, backup name and description to /api/openstack-dr-backups/ endpoint. DR backup has fields “state” and “runtime_state” that indicate backup creation progress.

It is possible to update DR backup name and description with POST request against /api/openstack-dr-backups/<uuid>/ endpoint.

To restore DR backup - issue POST request with DR backup, new tenant and new instance flavor against /api/openstack-dr-backup-restorations/ endpoint. Make sure that flavor is big enough for instance. You can check DR backup metadata to get stored instance minimum ram, cores and storage. On successful start of the restoration, endpoint will return URL of an instance that should will be created from DR backup, field “state” of this instance indicates restoration process progress.

To create a schedule of DR backups, use the same endpoint as for regular backups (/api/openstack-backup-schedules/) and additionally pass parameter “backup type” as “DR”.

For more detailed endpoints description - please check endpoints documentation.


In order to retrieve current version of the NodeConductor authenticated user should send a GET request to /api/version/.

Valid request example (token is user specific):

GET /api/version/ HTTP/1.1
Content-Type: application/json
Accept: application/json
Authorization: Token c84d653b9ec92c6cbac41c706593e66f567a7fa4

Valid response example:

HTTP/1.0 200 OK
Content-Type: application/json
Vary: Accept

    "version": "0.3.0"

Manage cost tracking as a staff

To initialize price list items click on the “init from registered resources” button. NodeConductor will populate price list items based on the installed plugins. If new plugin was installed - click on the “init from registered resources” button again and new plugin price items will be added.

Use button “delete not registered items” to delete outdated price list items that are not registered in installed plugins.

To update prices - first update all necessary price list items values and then click on the “recalulate current estimates” button to recalculate all estimates for current month using new prices.