|
| 1 | +janitor |
| 2 | +======= |
| 3 | + |
| 4 | +Janitor is a flask application for parsing provider maintenance notification emails and taking actions based on those emails. It's written to be easily extensible to your environment. |
| 5 | + |
| 6 | + |
| 7 | +# Overview |
| 8 | +Janitor connects to an email server on a user-specified interval and checks for any maintenance emails from a list of providers and adds them to the database. It can then be configured to take an action based on the type of email: new, update, cancel, reschedule, started, and ended. For instance, you can post updates to slack on maintenance start/end emails, add events to your calendar for new emails, remove events from your calendar for cancelled emails, etc. |
| 9 | + |
| 10 | +# Demo |
| 11 | + |
| 12 | + |
| 13 | +# Components |
| 14 | + |
| 15 | +## Mail Clients |
| 16 | +A mail client is configured with an email address, password, and port so that it can be connected to for email retrieval. Currently only gmail is supported. |
| 17 | + |
| 18 | +## Providers |
| 19 | +Currently supported providers include: |
| 20 | + - NTT * |
| 21 | + - PacketFabric * |
| 22 | + - EUNetworks * |
| 23 | + - GTT |
| 24 | + - Zayo |
| 25 | + |
| 26 | + |
| 27 | +The * Providers follow the [maint note](https://github.com/jda/maintnote-std/blob/master/standard.md) standard. |
| 28 | + |
| 29 | +# Configuration Options |
| 30 | + |
| 31 | +### PROJECT_ROOT |
| 32 | +The root folder of the janitor app. default: current working directory |
| 33 | + |
| 34 | +### SECRET_KEY |
| 35 | +Your application's secret key. This is required. |
| 36 | + |
| 37 | +### MAX_CONTENT_LENGTH |
| 38 | +Maximum size for circuit contract file uploads. default: 32 Mib |
| 39 | + |
| 40 | +### LOGFILE |
| 41 | +Location of the file that logs are written to. |
| 42 | + |
| 43 | +### CHECK_INTERVAL |
| 44 | +How frequently the mail server is checked for new messages. default: 10 minutes |
| 45 | + |
| 46 | +### POSTS_PER_PAGE |
| 47 | +The number of maintenances/circuits/providers to display on a single page. default: 20 |
| 48 | + |
| 49 | +### DATABASE_URL |
| 50 | +The location of the database. all databases supported by sqlalchemy are supported. default: current working directory + app.db |
| 51 | + |
| 52 | +### TZ_PREFIX |
| 53 | +For correctly modifying timezones. Some providers send maintenances with a timezone of "Eastern" instead of "US/Eastern" which breaks python datetime. You could set the TZ_PREFIX value to "US/" to fix this issue. default: None |
| 54 | + |
| 55 | +### MAIL_USERNAME |
| 56 | +Username for your mail server. This is required |
| 57 | + |
| 58 | +### MAIL_PASSWORD |
| 59 | +Password for your mail server. This is required |
| 60 | + |
| 61 | +### MAIL_SERVER |
| 62 | +imap address of your mail server |
| 63 | + |
| 64 | +### MAILBOX |
| 65 | +The name of the mailbox to process messages from. default: INBOX |
| 66 | + |
| 67 | +### MAIL_CLIENT |
| 68 | +The mail client you wish to use. currently only gmail is supported. This is required. |
| 69 | + |
| 70 | +### SLACK_WEBHOOK_URL |
| 71 | +If you wish to send messages to slack, you can define this. default: None |
| 72 | + |
| 73 | +### SLACK_CHANNEL |
| 74 | +The channel to post slack messages to. default: None |
| 75 | + |
| 76 | + |
| 77 | +# database schema |
| 78 | + |
| 79 | + |
| 80 | + |
| 81 | +# Setup |
| 82 | +Below walks through installation on ubuntu |
| 83 | + |
| 84 | +## Database |
| 85 | +You can choose any database you'd like. The example below uses mariadb. |
| 86 | +1. install mariadb |
| 87 | +``` |
| 88 | +apt install mariadb-server |
| 89 | +``` |
| 90 | +2. install mariadb dependencies |
| 91 | +``` |
| 92 | +apt install libmariadbclient-dev |
| 93 | +pip3 install mysqlclient |
| 94 | +``` |
| 95 | +3. create the database |
| 96 | +``` |
| 97 | +mariadb |
| 98 | +MariaDB [(none)]> create database janitor CHARACTER SET utf8; |
| 99 | +MariaDB [(none)]> CREATE USER 'janitor'@'localhost'; |
| 100 | +MariaDB [(none)]> GRANT ALL PRIVILEGES ON janitor.* TO 'janitor'@'localhost'; |
| 101 | +MariaDB [(none)]> quit |
| 102 | +
|
| 103 | +``` |
| 104 | + |
| 105 | + |
| 106 | +## requirements |
| 107 | +janitor requires python3.6 |
| 108 | + |
| 109 | +1. clone this repository into your desired installation directory |
| 110 | +2. create your virtual environment and activate it |
| 111 | +``` |
| 112 | +python3 -m venv venv |
| 113 | +source venv/bin/activate |
| 114 | +``` |
| 115 | +3. install the requirements |
| 116 | +``` |
| 117 | +pip3 install -r requirements.txt |
| 118 | +``` |
| 119 | +4. create a `.env` configuration files with the necessary variables. For example: |
| 120 | +``` |
| 121 | +PROJECT_ROOT='/opt/janitor' |
| 122 | +DATABASE_URL='mysql://janitor@localhost/janitor?charset=utf8' |
| 123 | +CHECK_INTERVAL=300 |
| 124 | +SLACK_WEBHOOK_URL='https://hooks.slack.com/abc123' |
| 125 | +SLACK_CHANNEL='#mychannel' |
| 126 | +MAIL_USERNAME='user@example.com' |
| 127 | +MAIL_PASSWORD='mypassword' |
| 128 | +MAIL_SERVER='imap.example.com' |
| 129 | +MAIL_CLIENT='Gmail' |
| 130 | +SECRET_KEY='mysecretkey' |
| 131 | +``` |
| 132 | +5. create the db schema: |
| 133 | +``` |
| 134 | +flask db init |
| 135 | +flask db migrate |
| 136 | +flask db upgrade |
| 137 | +``` |
| 138 | +6. You may wish to choose the providers you have in your network at this point, rather than selecting them all. You can do so by editing `app/jobs/main.py` and removing the ones you don't want in the `PROVIDERS` list |
| 139 | +7. From the providers you selected, you can define the email and type info under each provider's class in `app/Providers.py` types are one of: `transit`, `backbone`, `transport`, `peering`, and `facility`. |
| 140 | +8. at this point you can test connectivity to your server. First run the server: |
| 141 | +``` |
| 142 | +flask run -h 0.0.0.0 |
| 143 | +``` |
| 144 | +and then open a browser to your IP to see if you can connect. |
| 145 | + |
| 146 | + |
| 147 | +## Web/uwsgi Server |
| 148 | +It's not recommended to expose the flask app directly to the internet. Below we'll use nginx and gunicorn with supervisord for setup. It's also recommended to use https, though the the steps below only cover http |
| 149 | + |
| 150 | +1. install the packages |
| 151 | +``` |
| 152 | +apt install nginx supervisor |
| 153 | +pip3 install gunicorn |
| 154 | +``` |
| 155 | +2. create /etc/supervisor/conf.d/janitor.conf with the following contents: |
| 156 | +``` |
| 157 | +[program:janitor] |
| 158 | +command=/opt/janitor/venv/bin/gunicorn -b localhost:8000 -w 4 janitor:app --preload |
| 159 | +directory=/opt/janitor |
| 160 | +user=root |
| 161 | +autostart=true |
| 162 | +autorestart=true |
| 163 | +stopasgroup=true |
| 164 | +killasgroup=true |
| 165 | +``` |
| 166 | +3. create /etc/nginx/sites-enabled/janitor with the following contents: |
| 167 | +``` |
| 168 | +server { |
| 169 | + # listen on port 80 (http) |
| 170 | + listen 80; |
| 171 | + server_name _; |
| 172 | + access_log /var/log/janitor_access.log; |
| 173 | + error_log /var/log/janitor_error.log; |
| 174 | + location / { |
| 175 | + # forward application requests to the gunicorn server |
| 176 | + proxy_pass http://localhost:8000; |
| 177 | + proxy_redirect off; |
| 178 | + proxy_set_header Host $host; |
| 179 | + proxy_set_header X-Real-IP $remote_addr; |
| 180 | + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; |
| 181 | + } |
| 182 | +
|
| 183 | + location /static { |
| 184 | + # handle static files directly, without forwarding to the application |
| 185 | + alias /opt/janitor/app/static; |
| 186 | + expires 30d; |
| 187 | + } |
| 188 | +} |
| 189 | +``` |
| 190 | +4. restart nginx and supervisor |
| 191 | +``` |
| 192 | +supervisorctl reload janitor |
| 193 | +systemctl restart nginx |
| 194 | +``` |
| 195 | + |
| 196 | +janitor only checks for unread messages in your inbox. You may want to mark a few messages as unread to see if messages are being parsed at this point by navigating to your janitor server's IP, and either waiting until the next email check runs (it will tell you when this will be), or by using the "process emails" button to process immediately. Once the connection is successful you can stop the server with Ctrl-C |
| 197 | + |
| 198 | +# API |
| 199 | +The API has a UI and can be reached via the `/api/v1/ui/` endpoint for testing. |
| 200 | + |
| 201 | +## Endpoints |
| 202 | +All API endpoints need to be prefaced with `/api/v1`, for example, `/api/v1/circuits` |
| 203 | + |
| 204 | +### /circuits |
| 205 | +#### GET |
| 206 | +Get all circuits |
| 207 | +eg: |
| 208 | +`curl -X GET --header 'Accept: application/json' 'https://192.0.2.1/api/v1/circuits'` |
| 209 | + |
| 210 | +#### POST |
| 211 | +Create a new circuit by posting json. |
| 212 | +eg: |
| 213 | +``` |
| 214 | +curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' -d '{ \ |
| 215 | + "a_side": "string", \ |
| 216 | + "id": 0, \ |
| 217 | + "provider_cid": "string", \ |
| 218 | + "provider_id": 0, \ |
| 219 | + "z_side": "string" \ |
| 220 | + }' 'http://127.0.0.1:5000/api/v1/circuits' |
| 221 | +``` |
| 222 | + |
| 223 | +### /circuits/{circuit_id} |
| 224 | +#### GET |
| 225 | +Get a single circuit by the ID |
| 226 | +eg: |
| 227 | +`curl -X GET --header 'Accept: application/json' 'http://127.0.0.1:5000/api/v1/circuits/1'` |
| 228 | + |
| 229 | +#### PUT |
| 230 | +Update a circuit by posting json |
| 231 | +eg: |
| 232 | +``` |
| 233 | +curl -X PUT --header 'Content-Type: application/json' --header 'Accept: application/json' -d '{ \ |
| 234 | + "a_side": "string", \ |
| 235 | + "provider_id": 1 \ |
| 236 | + }' 'http://127.0.0.1:5000/api/v1/circuits/5' |
| 237 | +``` |
| 238 | + |
| 239 | +### /maintenances |
| 240 | +#### GET |
| 241 | +Get all maintenances |
| 242 | +eg: |
| 243 | +`curl -X GET --header 'Accept: application/json' 'http://127.0.0.1:5000/api/v1/maintenances'` |
| 244 | + |
| 245 | +### /maintenances/{maintenance_id} |
| 246 | +#### GET |
| 247 | +Get a maintenance by id |
| 248 | +eg: |
| 249 | +`curl -X GET --header 'Accept: application/json' 'http://127.0.0.1:5000/api/v1/maintenances/1'` |
| 250 | + |
| 251 | +### /providers |
| 252 | +#### GET |
| 253 | +Get all providers |
| 254 | +eg: |
| 255 | +`curl -X GET --header 'Accept: application/json' 'http://127.0.0.1:5000/api/v1/providers'` |
| 256 | + |
| 257 | +### /providers/{provider_id} |
| 258 | +#### GET |
| 259 | +Get a provider by id |
| 260 | +eg: |
| 261 | +`curl -X GET --header 'Accept: application/json' 'http://127.0.0.1:5000/api/v1/providers/1'` |
| 262 | + |
0 commit comments