Skip to content

Commit

Permalink
update docs and configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
jay-mckay committed Nov 6, 2024
1 parent 8f09852 commit 702701f
Show file tree
Hide file tree
Showing 9 changed files with 311 additions and 125 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ db.sqlite3
testing/warden/cgroup-warden
etc/*
!etc/settings.py
!etc/arbiter.service
!etc/arbiter-web.service
!etc/arbiter-eval.service
31 changes: 8 additions & 23 deletions arbiter/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,6 @@
except AttributeError:
raise ImproperlyConfigured("setting EMAIL_HOST is required")

try:
EMAIL_DISABLE_AUTH = ImproperlyConfigured("setting EMAIL_DISABLE_AUTH is required")
except AttributeError:
raise ImproperlyConfigured("setting EMAIL_DISABLE_AUTH is required")

try:
EMAIL_HOST_USER = settings.EMAIL_HOST_PASSWORD
except AttributeError:
Expand All @@ -67,14 +62,9 @@
raise ImproperlyConfigured("setting ARBITER_PROMETHEUS_URL is required")

try:
PROMETHEUS_DISABLE_SSL = settings.PROMETHEUS_DISABLE_SSL
PROMETHEUS_VERIFY_SSL = settings.PROMETHEUS_VERIFY_SSL
except AttributeError:
raise ImproperlyConfigured("setting PROMETHEUS_DISABLE_SSL is required")

try:
PROMETHEUS_DISABLE_AUTH = settings.PROMETHEUS_DISABLE_AUTH
except AttributeError:
raise ImproperlyConfigured("setting PROMETHEUS_DISABLE_AUTH is required")
raise ImproperlyConfigured("setting PROMETHEUS_VERIFY_SSL is required")

try:
PROMETHEUS_USER = settings.PROMETHEUS_USER
Expand All @@ -97,37 +87,32 @@
try:
WARDEN_PORT = settings.WARDEN_PORT
except AttributeError:
raise ImproperlyConfigured("setting WARDEN_JOB_PORT is required")
raise ImproperlyConfigured("setting WARDEN_PORT is required")

try:
WARDEN_DISABLE_SSL = settings.WARDEN_DISABLE_SSL
WARDEN_VERIFY_SSL = settings.WARDEN_VERIFY_SSL
except AttributeError:
raise ImproperlyConfigured("setting WARDEN_DISABLE_SSL is required")
raise ImproperlyConfigured("setting WARDEN_VERIFY_SSL is required")

try:
WARDEN_DISABLE_TLS = settings.WARDEN_DISABLE_TLS
WARDEN_USE_TLS = settings.WARDEN_USE_TLS
except AttributeError:
raise ImproperlyConfigured("setting WARDEN_DISABLE_TLS is required")

try:
WARDEN_DISABLE_AUTH = settings.WARDEN_DISABLE_AUTH
except AttributeError:
raise ImproperlyConfigured("setting WARDEN_DISABLE_AUTH is required")

try:
WARDEN_BEARER = settings.WARDEN_BEARER
except AttributeError:
raise ImproperlyConfigured("setting WARDEN_BEARER is required")

from prometheus_api_client import PrometheusConnect

if not PROMETHEUS_DISABLE_AUTH:
if PROMETHEUS_USER and PROMETHEUS_PASS:
auth = (PROMETHEUS_USER, PROMETHEUS_PASS)
else:
auth = None

PROMETHEUS_CONNECTION = PrometheusConnect(
url=PROMETHEUS_URL, auth=auth, disable_ssl=PROMETHEUS_DISABLE_SSL
url=PROMETHEUS_URL, auth=auth, disable_ssl=(not PROMETHEUS_VERIFY_SSL)
)

# FIXME this will hang if route is not reachable, timeout does not seem to work
Expand Down
19 changes: 9 additions & 10 deletions arbiter/eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@
ARBITER_PERMISSIVE_MODE,
ARBITER_NOTIFY_USERS,
ARBITER_MIN_UID,
WARDEN_DISABLE_AUTH,
WARDEN_DISABLE_SSL,
WARDEN_DISABLE_TLS,
WARDEN_VERIFY_SSL,
WARDEN_USE_TLS,
WARDEN_PORT,
WARDEN_BEARER,
)
Expand All @@ -28,24 +27,24 @@


async def set_property(target: Target, session: aiohttp.ClientSession, limit: Limit) -> tuple[http.HTTPStatus, str]:
if WARDEN_DISABLE_TLS:
endpoint = f"http://{target.host}:{WARDEN_PORT}/control"
else:
if WARDEN_USE_TLS:
endpoint = f"https://{target.host}:{WARDEN_PORT}/control"
else:
endpoint = f"http://{target.host}:{WARDEN_PORT}/control"

payload = {"unit": target.unit, "property": limit.json()}

if WARDEN_DISABLE_AUTH:
auth_header = None
else:
if WARDEN_BEARER:
auth_header = {"Authorization": "Bearer " + WARDEN_BEARER}
else:
auth_header = None
try:
async with session.post(
url=endpoint,
json=payload,
timeout=5,
headers=auth_header,
ssl=WARDEN_DISABLE_SSL,
verify_ssl=WARDEN_VERIFY_SSL,
) as response:
status = response.status
message = await response.text()
Expand Down
86 changes: 62 additions & 24 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,8 @@ Arbiter 3 was created for the Rocky 8 and 9 interactive systems at the Center fo
The core arbiter service is a Django application. This needs to be installed on a machine
with secure network access to Prometheus and the desired login nodes.

### Creating Arbiter service account
Arbiter needs to run under a service account.
```shell
groupadd arbiter
useradd -d /srv/arbiter -s /bin/false arbiter -g arbiter
```

### Installing Python 3.11
Python 3.11+ is required for the arbiter service, as is pip.

#### Installing from repositories
It is likely that your package manager has Python 3.11 available as a package. On Rocky 9.2+
Python 3.11+ is required for the arbiter service. It is likely that your package manager has Python 3.11 available as a package. On Rocky 9.2+, it can be installed with
```shell
sudo dnf install python3.11
```
Expand All @@ -30,32 +20,80 @@ pip is required as well.
python3.11 -m ensurepip --default-pip
```

### Installing source
### Installing the source code

First, we would like to specify the installation directory. A reasonable choice is `/opt/arbiter3`, but any directory with the proper permissions may be specified.
```shell
mkdir /opt/arbiter3
```

The Arbiter3 source code should be installed into a virtual environment.
```shell
python3.11 -m pip install
python3.11 -m venv /opt/arbiter3/venv
/opt/arbiter3/venv/bin/pip install 'arbiter @ git+http://github.com/chpc-uofu/arbiter'
```

This will install Arbiter as a module, as well as all of its dependencies in `arbiter-venv/lib/source-packages/arbiter`.

### Creating a Django Project
Arbiter is a Django app, and must be installed into a Django project to run. To create one,
```shell
/opt/arbiter3/venv/bin/django-admin startproject arbiter_django /opt/arbiter3
```
This will create some additional files such that
```
/opt/arbiter3/
manage.py
venv/
...
arbiter_django/
__init__.py
settings.py
urls.py
asgi.py
wsgi.py
```

#### Django Configuration
Django relies on the configuration in `settings.py`, which will need to be updated.
An example settings file is in [`etc/settings.py`](../etc/settings.py).
See [settings.md](settings.md) for details.

### Running the service
The arbiter service has two components, the web server and the core evaluation loop.
The arbiter service has two components, the web server and the core evaluation loop.

## cgroup-warden
#### Web Service
The arbiter web service can be run in a testing capacity with the following command:
```shell
venv/bin/python manage.py runserver
```
Which will listen on `localhost:8000`. For production, Arbiter should be run with Gunicorn. For example,
```shell
venv/bin/gunicorn arbiter.wsgi --bind 0.0.0.0:8000
```
Preferably, this will be set up behind a proxy such as NGINX.

### Install
See the [cgroup-warden](https://github.com/chpc-uofu/cgroup-warden/blob/main/INSTALL.md)
installation guide.
It should also be set up to run as a systemd service. See an example service file in [`etc/arbiter-wev.service`](../etc/arbiter-web.service)

### Configure
See the [cgroup-warden](https://github.com/chpc-uofu/cgroup-warden/blob/main/INSTALL.md#configure)
#### Evaluation Service
The arbiter evaluation loop can be run with
```
venv/bin/python manage.py evaluate
```
To run it in a loop, you can pass the `--seconds`, `--minutes`, or `--hours` flags.

This should also be set up to run as a service, see [`/etc/arbiter-eval.service`](../etc/arbiter-eval.service)


## cgroup-warden
See the [cgroup-warden](https://github.com/chpc-uofu/cgroup-warden/blob/main/INSTALL.md)
installation guide.

## Prometheus
### Install
See the [Prometheus](https://prometheus.io/docs/prometheus/latest/installation/) installation guide.

### Configure
For general configuration, see [here](https://prometheus.io/docs/prometheus/latest/configuration/).

Each cgroup-warden instance needs to be scraped. An example configuration might be
Each cgroup-warden instance needs to be scraped.
```yaml
scrape_configs:
- job_name: 'cgroup-warden'
Expand Down
139 changes: 139 additions & 0 deletions docs/settings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# Settings
The Arbiter Django app is configured with [Django Settings](https://docs.djangoproject.com/en/5.1/topics/settings/). Below describes the required settings for arbiter to run.

## General Django Settings

`DEBUG`: `bool`
...

`ALLOWED_HOSTS`: `list[str]`
- A list of hostnames from which the Arbiter site can be accessed from.
- Should be set to the fully qualified domain name of the server running arbiter.
- [Documentation](https://docs.djangoproject.com/en/5.1/ref/settings/#allowed-hosts)

`SECRET_KEY`: `str`
- A secret used for cryptographic signing and other security purposes.
- [Documentation](https://docs.djangoproject.com/en/5.1/ref/settings/#secret-key)

`INSTALLED_APPS`: `list[str]`
- Applications Django can use, Arbiter being one of them.
- [Documentation](https://docs.djangoproject.com/en/5.1/ref/settings/#installed-apps)

`ROOT_URLCONF`: `str`
...

`WSGI_APPLICATION`: `str`
...

`LOGIN_REDIRECT_URL`: `str`
...

`LOGOUT_REDIRECT_URL`: `str`
...

`TIME_ZONE`: `str`
...

`EMAIL_HOST`: `str`
...

`EMAIL_PORT`: `str`
...

`EMAIL_HOST_USER`: `str|None`
...

`EMAIL_HOST_PASSWORD`: `str|None`
...

`LOGGING`: `dict`
...

Example Settings:
```python
DEBUG = False
ALLOWED_HOSTS = ['your.arbiter.site.edu']
SECRET_KEY = 'your-super-secret-key'
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"django.contrib.humanize", # new
"arbiter", # new
]

ROOT_URLCONF = "arbiter.urls" # match exactly
WSGI_APPLICATION = "arbiter.wsgi.application" # match exactly
LOGIN_REDIRECT_URL = "/" # match exactly
LOGOUT_REDIRECT_URL = "/" # match exactly

TIME_ZONE = "America/Denver"
EMAIL_HOST = "your.mail.server.site.edu"
EMAIL_PORT = "25"
EMAIL_HOST_USER = None
EMAIL_HOST_PASSWORD = None
```

### Arbiter Specific Settings
`ARBITER_MIN_UID`: `int`
...

`ARBITER_PERMISSIVE_MODE`: `bool`
...

`ARBITER_USER_LOOKUP`: `str`
...

`ARBITER_NOTIFY_USERS`: `bool`
...

`ARBITER_EMAIL_DOMAIN`: `str`
...

`PROMETHEUS_URL`: `str`
...

`PROMETHEUS_VERIFY_SSL`: `bool`
...

`PROMETHEUS_USER`: `str|None`
...

`PROMETHEUS_PASS`: `str|None`
...

`WARDEN_JOB`: `str`
...

`WARDEN_PORT`: `int`
...

`WARDEN_VERIFY_SSL`: `bool`
...

`WARDEN_USE_TLS`: `bool`
...

`WARDEN_BEARER`: `str|None`
...

Example settings:
```python
ARBITER_MIN_UID = 1000
ARBITER_PERMISSIVE_MODE = False
ARBITER_USER_LOOKUP = "arbiter.utils.default_user_lookup"
ARBITER_NOTIFY_USERS = True
ARBITER_EMAIL_DOMAIN = "test.site.edu"
PROMETHEUS_URL = "http://prometheus:9090"
PROMETHEUS_VERIFY_SSL = True
PROMETHEUS_USER = None
PROMETHEUS_PASS = None
WARDEN_JOB = "cgroup-warden"
WARDEN_PORT = 2112
WARDEN_VERIFY_SSL = False
WARDEN_USE_TLS = False
WARDEN_BEARER = "super-secret-bearer-token"
```
10 changes: 10 additions & 0 deletions etc/arbiter-eval.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Unit]
Description=Arbiter Evaluation Loop
After=network.target

[Service]
Type=simple
Environment=DJANGO_SETTINGS_MODULE="arbiter_django.settings"
WorkingDirectory=/opt/arbiter3
ExecStart=/opt/arbiter3/venv/bin/python manage.py evaluate --seconds 30
ExecReload=/bin/kill -s HUP $MAINPID
Loading

0 comments on commit 702701f

Please sign in to comment.