Raspberry Pi Cluster Node – 14 A simple webserver

This tutorial focuses on creating a simple webserver that displays the status of the master using python Bottle.

What will the webserver be used for?

To interact with the cluster I am planning on making a small set of webpages. Initially these will just display information about the cluster but going forward they will be able to schedule tasks to run on the cluster.

This will allow more feature rich ways of interacting with the cluster. It will operate like another slave, but this one will be in charge of running the webserver.

For the first stage I am going to be making the webserver output information about the master.

What is Python Bottle

Python Bottle is a lightweight library which can be used to host a small webserver. This works with a simple WSGI server that reacts to the HTTP requests.

In production you should really attach it to a full webserver which will handle the requests instead of using the inbuilt WGSI server. However for our purposes this will work fine we we wont need it to handle a large number of requests.

If this becomes too slow then there are options to move to using a webserver like NGINX.

Creating the Webserver Slave

The basic webserver will revolve around a single webserver slave which will talk to the master to obtain information about the cluster.

Initially it will just poll the master for information and cache this. Then when a user requests the information via the webserver this cached information will be presented. In a later tutorial the webserver will make direct requests for specific information to the master.

Below is the basic webserver slave thread class.

class RpiWebserverSlaveThread(RpiBasicSlaveThread):

    current_webserver_data = None
    webserver_data_updated = None

    def perform_action(self):
        logger.info("Now sending a keepalive to the master")
        send_message(self.sock, create_payload("I am still alive, client: {num}".format(num=self.client_number)))
        send_message(self.sock, create_payload("computer_details", "info"))
        message = get_message(self.sock)
        RpiWebserverSlaveThread.current_webserver_data = message['payload']
        RpiWebserverSlaveThread.webserver_data_updated = datetime.datetime.now()
        time.sleep(5)

This is a subclass of the basic RpiBasicSlaveThread class which was refactored in the previous tutorial. This refactoring has allowed all the base code to be kept the same and just the perform_action function to be overridden.

This overridden method will request the information about the master and save it to a static class variable.

Creating the simple webserver

Python Bottle allows you to create a very simple webserver. Again it must be noted that using the inbuilt server is not appropriate for large applications but for us it works fine.

@route('/')
def index():
    return template("templates/ClusterHomepage.html",
                    info=json.dumps(RpiWebserverSlaveThread.current_webserver_data, indent=4, sort_keys=True))

run(host=webserver_host, port=webserver_port)

Here we define an index method and annotate it with a route annotation from Python Bottle. This will associate it to the base webserver and add it as a handler for the “/” base route.

When called, it will open the ClusterHomepage.html and replace the {{info}} text with the value of the info variable. In this case it will be the following.

json.dumps(RpiWebserverSlaveThread.current_webserver_data, indent=4, sort_keys=True))

This includes the current cached information about the master on the webpage and then serves it to the client.

The HTML page that is used as a template is reproduced below.

<!doctype html>
<html lang="en">
<head>
  <title>Raspberry Pi Cluster</title>
  <meta name="description" content="Raspberry Pi Cluster Homepage">
  <meta name="author" content="Christopher Hewett">
</head>

<body>
<h1>Raspberry Pi Cluster Homepage</h1>

<p>This page shows the status of the Raspberry Pi Cluster</p>

<h2>Master Information</h2>
<pre>{{info}}</pre>

</body>
</html>

The final line then starts up the webserver on the given port and hostname. To associate the webserver to all hostnames you can set it to 0.0.0.0. This will make it easily publicly accessible to other computers on the same network.

Once this is done and loaded it will look like this.

Summary of the changes

In this tutorial a new slave is made which will continually request data from the master. This slave also starts a small Python Bottle webserver which will allow viewing of this data.

Currently there is nothing that the webserver can request to be performed so this will be the focus in future tutorials.

The full code is available on Github, any comments or questions can be raised there as issues or posted below.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.