- The host operating system must be able to run bash commands. The dashboard should work with Mac OS, Linux and WSL.
- Docker must be functional on the host operating system.
- Clone this GitHub repository and navigate into it before running the commands.
The format of the API credentials for Aruba Central and Aruba ClearPass is declard in the file creds_template.py
.
It can also be found below in the chapter creds_template.py.
Create a file called config.py
in the root directory of the project. Contents of the configuration file can be found below in the config.py chapter.
Start container:
docker compose up -d
View logs of container (requires container to be running):
docker compose logs -f
The command to start the container can also be combined with the command to view the logs:
docker compose up -d && docker compose logs -f
Stop container:
docker compose down
.
├── .gitignore
├── app.py
├── config.py
├── docker-compose.yaml
├── Dockerfile
├── README.md
├── requirements.txt
├── temp
└── tok_{customer-id}_{random-numbers}.json
├── app
└── central_devices.py
└── change_vlan.py
└── creds_template.py
└── group_config.py
└── utils.py
└── clearpass
└── __init__.py
└── api.py
└── static
└── favicon.ico
└── logo.svg
└── styles.css
└── templates
└── base.html
└── central-devices.html
└── change-vlan.html
└── index.html
Defines the services in the container.
- The service
web
builds the current container using the Dockerfile. - It exposes port
5002
on your machine and maps it to port5000
in the container. You can change port5002
freely, as this is only has an impact on your local machine. - It maps the current directory on your local machine to the directory
/app
within the container.
Defines how the container should be built.
- Pull an Ubuntu container image.
- Set
/app
as the working directory. - Run the command
apt update
to update the container image. - Run the command
apt install python3-pip -y
to install Python3 and the pip package manager. The-y
tag ensures that any prompts during the command are answered with yes. - Copy the file
requirements.txt
from your local machine into the working directory of the container. - Run the command
pip3 install -r requirements.txt
. This uses the pip package manager to install all the requirements inrequirements.txt
. - Expose port 5000 in the container. This is needed to be able to map the port to a port on your local machine.
- Copy the contents of the root folder of the project on your local machine to the working directory in the container.
- Set the environment variables
FLASK_APP
toapp
andFLASK_ENV
todevelopment
- Run the command
python3 -m flask run --host=0.0.0.0
. This runs the app using the python module flask on the host (within the container)0.0.0.0
.
All the files that shouldn't be commited to GitHub get added to the .gitignore
file.
Already added here are:
- Bytecode generated by Python.
- API credentials, that have to be kept secret.
- The config file
config.py
. - The
temp
folder which is created bypycentral
for token handling.
The app.py
file is the base of the project. Here an instance of Flask is created and all Flask specific settings are set.
Additionally all routes are defined here. Explanations for all routes can be found in the docstring and comments for each function.
The config.py
file is only needed in order to set a secret key. This is a requirement for the flash
module in Flask.
The secret key must be a hexadecimal String, but the length does not matter directly. The longer the better, but no need to go crazy.
# Set secret key variable, needed for flash module in Flask
SECRET_KEY = '{hexadecimal String}'
Specify the requirements for the dashboard:
- Flask - Makes the app.
- Jinja2 - Used to create the html templates.
- pycentral - API driver for Aruba Central
Contains the API driver for Aruba Central.
Contains static content:
- Favicon displayed in bookmarks and tabs.
- Logo file displayed top left in the navbar.
- CSS styles file defining how the table at route
/central-devices
should look.
Contains all html templates.
Base html file, which all other templates are based on. The following things happen here:
- Meta tags are set.
- Bootstrap link is included.
- Aruba favicon is set.
- Title is set using Jinja2 variable.
- Style is set for the navbar.
- Navbar is defined.
- Content block is defined in the body.
- Bootstrap alerts are defined based on Flask flash messages.
HTML file to display table of all devices in Aruba Central. The following things happen here:
- The
base.html
template is extended. - The title variable is filled.
- The content variable is filled with a table of central devices.
- The table takes data which is passed to the template through the variables
headings
anddata
. - Programmatically through Jinja2 it takes each header from the headings and writes it into a table header tag.
- For each row in the data it then writes elements 1 to 9 from the row of data into a table item. Attention: element 0 of the row of data is the index does not have to be displayed.
- For each row of data a button is rendered. The button acts as a submit button for a form and hidden input field. Via this button the values row ID, MAC Address and VLAN ID are submitted to
/change-vlan
via a POST request. There they are then displayed in the input fields.
HTML file to input and submit MAC Address and VLAN ID. The following things happen here:
- The
base.html
template is extended. - The title variable is filled.
- A form with a POST request to
/change-vlan
is defined. - Within this two input fields and a submit button sit. The input fields are to input the MAC Address and VLAN ID. The submit button triggers the post request.
HTML file to display the homepage. The following things happen here:
- The
base.html
template is extended. - The title variable is filled.
- Two buttons are defined for the two 'modules' within the dashboard: The 'Change VLAN ID' and 'Central Devices' modules.
This Python file handles everything related to displaying the devices from Aruba Central at /central-devices
.
- Firstly the
ArubaCentralBase
is imported frompycentral.base
and the credentials for Aruba Central are imported fromcreds_central
. - An instance of the ArubaCentralBase is created with
ssl_verify
set to true. The credentials are passed to the constructor andtoken_store
is set toNone
. - The function
get_clients()
gets all wired and wireless clients from Aruba Central and returns a tuple of headings and clients to be displayed in table at/central-devices
. - A tuple of headings is declared. To change the headings of the table at
/central-devices
edit this tuple. - Using
central.command
, two GET requests are made for all wired and wireless clients in Aruba Central. - The two responses are combined into one list.
- Using a for loop to loop through all clients, for each client the values matching the headings are appended to the
return_clients
list. - A tuple of headings and client attributes is returned.
This file controls everything to do with how the dashboard accesses the Aruba ClearPass API to change the VLAN ID of a client. The following things happen here:
- External and internal (from Python files in directory) imports are handled.
- The host and access token are read from the ClearPass credential file.
- A ClearPass API client is declared with the host and access_token variables.
This function calls the individual procedures that are part of changing the VLAN ID:
- Validate the MAC Address.
- Validate the VLAN IP.
- Changing the vlan_id attribute for a device.
- Retrieving the session_id associated to the mac_addr.
- Reauthorizing the session associated to the session_id.
The responses of the procedure calls are added to a list, which is then returned.
For the MAC validation, VLAN validation and retrieving the session ID, the function call is within a try, except block. This is used, because the information returned in a possible error is used to flash a message.
This function retrieves endpoint information for the mac_addr. It is not actively used in the procedure to change the vlan_id, but was used in the development process to retrieve information.
The following things happen here:
- The URL for the API is constructed.
- A GET request is sent to the URL.
- API Errors and Configuration Exceptions are caught, a flash message is triggered and the same message is returned.
This function changes the the vlan_id attribute in the endpoint information.
The following things happen here:
- The URL for the API is constructed.
- The request body is constructed. Here the vlan attribute is set to the vlan_id variable.
- A PATCH request is sent to the URL with the body.
- API Errors and Configuration Exceptions are caught, a flash message is triggered and the same message is returned.
- If no error is triggered, a success message is flashed.
- The response is returned
This function retrieves the session_id for specified mac_addr.
The following things happen here:
- The URL for the API is constructed.
- A GET request is sent to the URL.
- API Errors and Configuration Exceptions are caught, a flash message is triggered and the same message is returned.
- The session items are extracted from the response and the length of the item list is saved in a variable.
- We loop through the session items. For each item the mac_address attribute is matched to the mac_addr variable and the state attribute is matched to 'active'.
- The id attribute is returned.
This function reauthorizes the session of client with session_id variable.
The following things happen here:
- The URL for the API is constructed.
- The request body is constructed. The attribute 'confirm_reauthorize' is set to True and 'reauthorize_profile' is set to '[AOS-CX - Bounce Switch Port]'.
- A POST request is sent to the URL.
- API Errors and Configuration Exceptions are caught, a flash message is triggered and the same message is returned.
- If no error is triggered, a success message is flashed.
- The response is returned
This files defines how the API credentials for Aruba ClearPass and Aruba Central must be declared for the dashboard to function properly.
You MUST configure the 'host' member variable and one of the following for authorization:
- access_token (if you already performed OAuth2 authentication)
- client_id, client_secret (implies grant_type=client_credentials)
- client_id, username, password (implies grant_type=password, public client)
- client_id, client_secret, username, password (implies grant_type=password)
Copy the following block into a new file and name it 'creds_cppm.py'. Then configure the following variables as required.
cppm_info = {
'username': '',
'password': '',
'client_id': '',
'client_secret': '',
'access_token': '',
'host': ''
}
Copy the following block into a new file and name it 'creds_central.py'. Then configure the following variables as required.
central_info = {
"client_id": "",
"client_secret": "",
"customer_id": "",
"base_url": "",
}
This files contains utilities for specific use cases within the dashboard.
This function is used to change the mac_addr variable into the format for the API.
The format is changed to uppercase and the separator is changed to -
.
This function is used to validate the mac_addr variable.
- An AssertionError is raised if the mac_addr variable is empty.
- Through regex the format of the MAC Address is validated. An AssertionError is raised if the format is incorrect.
This function is used to validate the vlan_id variable.
- An AssertionError is raised if the vlan_id variable is empty.
- By trying to convert the vlan_id String to int it can be validated if the passed variable is an int. If not, an AssertionError is raised.
This function is used to parse out row_id, mac_addr and vlan_id from the passed String values.
- The values String is split into a list, using
,
as the list separator. - The first item of the newly created list is assigned to row_id. The first character is
[
and is cut using[1:]
. - The second item is assigned to mac_addr. The first and last characters are spaces and are cut using
[1:-1]
. - The third item is assigned to vlan_id. The last character is
]
and is cut using[:-1]
. - A tuple of row_id, mac_addr and vlan_id is returned.
Below are the flash messages, which can be shown in the dashboard.
flash('Success! Nothing happened.', 'success')
flash('Info! Something changed.', 'info')
flash('Warning! Something happened.', 'warning')
flash('Danger! Something broke.', 'danger')