1 Install Ganeti Manager (ganetimgr)

Note: This is partly based on the instructions at

https://ganetimgr.readthedocs.io/en/latest/install.html and https://ganetimgr.readthedocs.io/en/latest/version2.html

with some modifications (v2.0)

1.1 Run this as root

Most of the commands below will require root access, so we'll start by going to the root user (use su or sudo)

$ sudo -s
Password:

#

1.2 Install required packages

We'll need to be installing some packages from the backports repository, to avoid problems in the "stock" version of the packages that ship with Debian 8.

If you haven't already done so, create the file /etc/apt/sources.list.d/jessie-backports.list with the following contents:

deb http://httpredir.debian.org/debian/ jessie-backports main contrib non-free

Now, run apt-get update (as root) to update the package lists.

Next, we install the packages:

# apt-get install -t jessie-backports python-django gunicorn python-gevent

The rest of the packages we can install normally:

# apt-get install git nginx mysql-server beanstalkd memcached \
    python-dev python-mysqldb python-paramiko python-ipaddr python-pycurl \
    python-memcache python-bs4 python-recaptcha gettext python-daemon \
    python-setproctitle python-django-jsonfield python-beanstalkc python-pip

When prompted for a password for the mysql root user, pick one and remember it.

A few remaining packages needs to be instaled using pip:

pip install django-registration-redux vncauthproxy

We'll create a startup script for the VNC proxy we just installed.

Create the file /lib/systemd/system/vncauthproxy.service

# editor /lib/systemd/system/vncauthproxy.service

And paste in the following lines:

[Unit]
Description=VNC AuthProxy
After=network.target auditd.service

[Service]
Environment='PIDFILE=/var/run/vncauthproxy/proxy.pid'
Environment='LOGFILE=/var/log/vncauthproxy/proxy.log'
Environment='PORT=8888'
Environment='INTERFACE=0.0.0.0'
EnvironmentFile=-/etc/default/vncauthproxy
ExecStart=/usr/local/bin/twistd --pidfile=${PIDFILE} --nodaemon --logfile=${LOGFILE} vncap -c tcp:${PORT}:interface=${INTERFACE}

[Install]
WantedBy=multi-user.target
Alias=vncauthproxy.service

Create the log and PID directories:

# mkdir /var/log/vncauthproxy
# mkdir /var/run/vncauthproxy

Now enable and start the service:

# systemctl enable vncauthproxy
# systemctl start vncauthproxy

You can verify it's running:

# ps ax | grep twistd
# tail /var/log/vncauthproxy/proxy.log

We have now started the VNC Auth Proxy that will allow for browser-based VNC consoles.

1.3 Create database

# mysql -u root -p
Enter password: <passwork picked earlier here>

mysql> CREATE DATABASE ganetimgr CHARACTER SET utf8;
mysql> CREATE USER 'ganetimgr'@'localhost' IDENTIFIED BY '<PICK_A_PASSWORD>';
mysql> GRANT ALL PRIVILEGES ON ganetimgr.* TO 'ganetimgr';
mysql> flush privileges;
mysql> exit

Test that the created database works:

# mysql -u ganetimgr -p ganetimgr
Enter password: <password_for_ganetimgr_db_user>

mysql> exit

1.4 Check out the stable version of Ganetimgr

# mkdir /srv/
# mkdir /var/log/ganetimgr
# cd /srv/
# git clone https://www.ws.nsrc.org/ganetimgr
# cd ganetimgr
# git checkout v2.0

Note: the "official" Git repo for GanetiMGR is here:

https://github.com/grnet/ganetimgr.git

... but we clone from the local copy on www.ws.nsrc.org so we don't have to wait too long.

1.4.1 Copy the default settings for ganetimgr end edit them

# cd ganetimgr
# cp settings.py.dist settings.py
# editor settings.py

The following changes will need to be made

The first change to be made is to find:

ALLOWED_HOSTS = [
    '.example.com',  # Allow domain and subdomains
    '.example.com.', # Also allow FQDN and subdomains
]

and change it to:

ALLOWED_HOSTS = [
    '127.0.0.1',
]

Then, find the section:

ADMINS = (
    ('John Doe', 'john@example.com'),
)

Change the line above, adding and entry for the main admin user, for example:

ADMINS = (
    ('admin','your@email.address'),
)

Next, find the DATABASES section, and the line:

'ENGINE' : 'django.db.backends.',

And change it to:

'ENGINE' : 'django.db.backends.mysql'

This tells the Django application framework that we'll be using MySQL as a backend.

Next, set the NAME, USER and PASSWORD to those of the database you created earlier:

'NAME' : 'ganetimgr',            # Or path to database file if using sqlite3.
'USER' : 'ganetimgr                       # Not used with sqlite3.
'PASSWORD' : '<PASSWORD_PICKED_EARLIER>', # Not used with sqlite3.

Set TIME_ZONE to your location, for instance:

TIME_ZONE = 'Africa/Nairobi'

Next, find the section:

SECRET_KEY = <CHANGE_ME>

And change it to a random string, for example:

SECRET_KEY = 'wlj84oaliehgzi48ol9qo3ijhesrbykjdzn,.38h,u4gbrg'

Please, don't copy the above key! Generate your own!

Comment out the sections OPERATING_SYSTEM_URLS and SNF_OPERATING_SYSTEMS_URLS for the time being, so they look like:

# OPERATING_SYSTEMS_URLS = ['http://repo.noc.grnet.gr/images/']
# SNF_OPERATING_SYSTEMS_URLS = ['http://repo.noc.grnet.gr/images/snf-image/']

Next, find SERVER_EMAIL and DEFAULT_FROM_EMAIL and set them accordingly, for example:

SERVER_EMAIL = "ganetimgr@ganetimgr.ws.nsrc.org"
DEFAULT_FROM_EMAIL = "ganetimgr@ganetimgr.ws.nsrc.org"

Find COLLECTD_URL, and comment it out:

# COLLECTD_URL = "http://stats.example.com"

Find the section concerning the websockets console:

# This is meant to be used with twistednovncauthproxy
# twistd --pidfile=/tmp/proxy.pid -n vncap -c tcp:8888:interface=0.0.0.0
NOVNC_PROXY = "example.com:8888"
NOVNC_USE_TLS = True

And change it as follows:

NOVNC_PROXY = "ip.of.this.machine:8888"
NOVNC_USE_TLS = False

... where ip.of.this.machine is the IP of the machine that ganetimgr is being installed on. It's preferable to use a hostname, i.e.: ganetimgr.ws.nsrc.org.

Set up caching - find the CACHING section:

#CACHES = {
#     'default': {
#         'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
#         'LOCATION': '127.0.0.1:11211',
#         'TIMEOUT': 1,
#     }
#}

And uncomment it, so it looks like this:

CACHES = {
     'default': {
         'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
         'LOCATION': '127.0.0.1:11211',
         'TIMEOUT': 1,
     }
}

Find the line:

NODATA_IMAGE = 'static/nodata.gif'

And change it to:

NODATA_IMAGE = 'static/ganetimgr/img/nodata.jpg'

Find:

TEST_RUNNER = 'django.test.simple.DjangoTestSuiteRunner'

and replace it with

TEST_RUNNER = 'django.test.runner.DiscoverRunner'

Lastly, find the BRANDING section and update it with the information for your organization.

1.5 Populate the database

Finally, it's time to get the database populated and create a user:

# cd /srv/ganetimgr
# python manage.py syncdb --noinput

If everything goes well some output about tables being created will scroll past, and end with something similar to:

...
  Applying ganeti.0003_auto_20170807_1459... OK
  Applying notifications.0001_initial... OK
  Applying sessions.0001_initial... OK

One more command to run:

# python manage.py migrate

Again, some output will flash by. If nothing needed to be done, it should end with:

...
Running migrations:
  No migrations to apply.

Now, let's create a user:

# python manage.py createsuperuser

Here, we'll create an admin user, so at the question:

Username (leave blank to use 'root'):

Enter admin

Next, you'll be prompted for an email address. Here, you can enter your email address, although for testing it might be better to start by using the mail address of the local user, root@ganetimgr.ws.nsrc.org.

Finally, you'll be asked to provide a password. Don't use something too easy to guess when deploying this in production!

If all goes well, you'll see:

Superuser created successfully.

1.6 Create the admin interface page

The next command creates the pages that will be displayed in the administrative interface:

# cd /srv/ganetimgr
# python manage.py collectstatic

You will be prompted:

This will overwrite existing files!
Are you sure you want to do this?

Type 'yes' to continue, or 'no' to cancel:

Answer yes and press <enter>.

1.7 Start the watcher process

This is responsible for tracking the state of jobs (tasks)

We'll create a startup script for the GanetiMgr Watcher

Create the file /lib/systemd/system/ganetimgr-watcher.service

[Unit]
Description=GanetiMgr watcher
After=network.target auditd.service

[Service]
Environment='PIDFILE=/var/run/ganetimgr-watcher/ganetimgr-watcher.pid'
Environment='LOGFILE=/var/log/ganetimgr/watcher.log'
ExecStart=/srv/ganetimgr/watcher.py

[Install]
WantedBy=multi-user.target
Alias=ganetimgr-watcher.service

Create the log directory:

# mkdir /var/run/ganetimgr-watcher

Now enable and start the service:

# systemctl enable ganetimgr-watcher
# systemctl start ganetimgr-watcher

Verify that it is running:

# ps ax | grep watcher.py

1.8 Create a configuration for gunicorn

gunicorn is a python web server, which will run the Ganeti Manager application.

We'll start by using a sample configuration provided with ganetimgr:

# mkdir /etc/gunicorn.d
# cd /srv/ganetimgr
# cp contrib/gunicorn/ganetimgr_jessie /etc/gunicorn.d/ganetimgr

Now edit the file /etc/gunicorn.d/ganetimgr, and update the config section to look like:

CONFIG = {
    'mode': 'wsgi',
    'user': 'www-data',
    'group': 'www-data',
    'args': (
        '--chdir=/srv/ganetimgr',
        '--bind=0.0.0.0:8088',
        '--workers=2',
        '--worker-class=gevent',
        '--timeout=30',
        '--log-file=/var/log/ganetimgr/ganetimgr.log',
        'ganetimgr.wsgi:application',
    ),
}

1.9 Restart gunicorn

# service gunicorn restart

1.10 Create an Nginx configuration

Nginx, the web server, runs as the "front-end" for gunicorn.

Here's a minimal configuration get the web interface up and running:

Edit the file /etc/nginx/sites-enabled/default, erasing ALL THE LINES IN THE FILE, and copy the following lines into it:

server {
        server_name ganetimgr.ws.nsrc.org;  # replace with your hostname

        location / {
                proxy_pass http://127.0.0.1:8088;
        }

        location /static {
                root   /srv/ganetimgr;
        }
}

Test the configuration:

# service nginx configtest

And if all is well, proceed to restart nginx:

# service nginx restart

2 Create RAPI user

We now need to create a user on the Ganeti cluster nodes, that will allow Ganeti Manager to control the cluster.

Pick a random string (for example, generate it with):

head -c18 /dev/urandom | base64

... and run it through the following command (replace 'random_string' with the output from the previous command)

echo -n 'ganetimgr_api_user:Ganeti Remote API:random_string' | openssl md5

Note that random string should probably not contain ':'.

Here's a sample output, which is a hashed password:

b20990f88c544cea982645e99b08d8c8

The final authentication / authorization line will look like this:

ganetimgr_api_user {HA1}b20990f88c544cea982645e99b08d8c8 write

... where write indicates that this user ganetimgr_api_user has write access to the cluster (i.e: can modify/create/delete instances!)

Now, on the master node (NOT ON THE GANETIMGR MACHINE!), create the following file (as root):

# editor /var/lib/ganeti/rapi/users

... and copy the authentication/authorization line, with the correct hashed password.

Once you've done this, distribute this file to the other nodes in the cluster with the following command:

# gnt-cluster copyfile /var/lib/ganeti/rapi/users

We have to make one more change, so that the Ganeti RAPI (Remote API) becomes reachable over the network - for security reasons, it's disabled by default.

To make this happen, on the master node, edit the ganeti daemon config file:

# editor /etc/default/ganeti

And change the line:

RAPI_ARGS="-b 127.0.0.1 --require-authentication"

So it looks like:

RAPI_ARGS="--require-authentication"

... save the file and exit.

Copy the file to all nodes:

# gnt-cluster copyfile /etc/default/ganeti

And finally, restart Ganeti:

# service ganeti restart

That's it! We are now ready to test the front-end!

3 Navigate to the ganetimgr web interface.

Open http://ganetimgr.ws.nsrc.org/ in your browser.

You should be presented with the login screen.

Login with the admin user and password you created earlier.

Now, click on Admin in the top menu.

Click on Add next to Clusters under the Ganeti section.

For hostname, enter the hostname (it must be in the DNS!) of the cluster, i.e.: gnt.ws.nsrc.org.

For the "Slug", you can put "nsrc" for instance. It's best to avoid '-' in the cluster name, it seems.

For username, use the ganetimgr_api_user specified earlier.

For password, you use the randomly generated password (NOT the hashed version!) created earlier.

Click Save

Now it's time to navigate back to the mainpage:

`http://ganetimgr.ws.nsrc.org`

At this point, we are ready to add VMs!

4 Additional notes

4.1 What's missing ?

4.2 Issues with VNC consoles and using /etc/hosts on ganetimgr

We have the cluster node names and the ganetimgr host names in /etc/hosts as vncauthproxy uses gevent and greenlets for the event loop and connection handling / forwarding. gevent (<1.0beta) uses libevent2 and its async DNS resolver, and libevent2-dns doesn't read /etc/hosts.

4.3 Issues with Bad Gateway 502

If you get this when trying to open the web page for ganetimgr, then check the Gunicorn log:

# tail -f /var/log/ganetimgr/ganetimgr.log

If you see the error "ImportError: No module named urls"

... then you may need to make the following change.

# cd /srv/ganetimgr
# editor accounts/urls.py

Find the line:

    (r'^', include('registration.backends.admin_approval.urls')),

And comment it out:

    # (r'^', include('registration.backends.admin_approval.urls')),

Save the file and exit, then restart the Gunicorn server:

# service gunicorn restart