Debian setup notes - kawajanagi/mwa2 GitHub Wiki

Following are some notes on installing MWA2 on Debian 12 (Bookworm). Other Linux distros should be similar. There are a few additional notes for other related distros.

Install virtualenv

apt install python3-venv

On Debian 12, virtualenv can be installed by apt apt install python3-venv. You will also need to install Python version 3 so that you can later use use it for your virtual environment apt install python3. If you do not install python3 so you can use it for your virtual environment, you will have syntax errors later when you try to run mwa2/manage.py

Create a virtual environment for MWA2

# cd /some/path/you/want/to/use
# virtualenv mwa2_env
New python executable in mwa2_env/bin/python
Installing setuptools, pip, wheel...done.

On Debian 12, you will need to have virtualenv create an environment running python 3 python3 -m venv mwa2_env. Without this step, you will have syntax errors later when you try to run mwa2/manage.py

Activate the virtual environment

# cd mwa2_env

If you aren't using bash as your interactive shell, type bash and hit return

# source bin/activate
(mwa2_env)#

Install the Python dependencies

(mwa2_env)# pip install Django==4.2.11
(mwa2_env)# pip install gunicorn==20.1.0

(optional, if you plan to setup LDAP authentication)

(mwa2_env)# pip install django-auth-ldap

Clone the MWA2 code into the mwa2 virtual environment

If you changed directories at any point, make sure you are in the mwa2_env directory:

(mwa2_env)# cd /path/to/mwa2_env

Clone the mwa2 code from GitHub:

(mwa2_env)# git clone https://github.com/munki/mwa2.git
Cloning into 'mwa2'...
remote: Enumerating objects: 1444, done.
remote: Counting objects: 100% (59/59), done.
remote: Compressing objects: 100% (46/46), done.
remote: Total 1444 (delta 15), reused 28 (delta 8), pack-reused 1385 (from 1)
Receiving objects: 100% (1444/1444), 2.00 MiB | 3.99 MiB/s, done.
Resolving deltas: 100% (704/704), done.

Clone the munkitools into the virtual environment

MWA2 makes use of makecatalogs from Munki. You can just copy it locally into the virtual environment, or you can do what we do here, which is to clone the entire Munki project here, which allows us to update makecatalogs easily with a future git pull.

(mwa2_env)# git clone https://github.com/munki/munki.git
Cloning into 'munki'...
remote: Enumerating objects: 35375, done.
remote: Counting objects: 100% (1697/1697), done.
remote: Compressing objects: 100% (538/538), done.
remote: Total 35375 (delta 1418), reused 1239 (delta 1157), pack-reused 33678 (from 3)
Receiving objects: 100% (35375/35375), 20.88 MiB | 4.73 MiB/s, done.
Resolving deltas: 100% (25164/25164), done.

Duplicate and edit settings.py

(mwa2_env)# cp mwa2/munkiwebadmin/settings_template.py mwa2/munkiwebadmin/settings.py

Edit line 224 of mwa2/munkiwebadmin/settings.py, pointing MUNKI_REPO_DIR to the filesystem path to your repo

###########################################################################
# munkiwebadmin-specific
###########################################################################

# APPNAME is user-visible web app name
APPNAME = 'MunkiWebAdmin2'
# MUNKI_REPO_DIR holds the local filesystem path to the Munki repo
MUNKI_REPO_DIR = '/mnt/munki_repo'
#MUNKI_REPO_DIR = '/Volumes/repo

Edit line 242 of mwa2/munkiwebadmin/settings.py to point MAKECATALOGS_PATH to a copy of the makecatalogs tool. If you used git clone to get a copy of the Munki tools as suggested above, it will be in the munki/code/client/ directory.

# path to the makecatalogs binary
MAKECATALOGS_PATH = '/path/to/mwa2_env/munki/code/client/makecatalogs'

Add the following line at the end of the file to refer to the FQDN of the main Apache2 website that will be allowed to talk to the Gunicorn server so that it's the only site that can do unsecure requests to Gunicorn. This is especially true if leveraging HTTPS.

# URL to the main Apache2
CSRF_TRUSTED_ORIGINS = ['https://hostname.company.com:443']

#### Initialize the app database

(mwa2_env)# python mwa2/manage.py migrate Operations to perform: Apply all migrations: sessions, admin, auth, manifests, process, contenttypes, pkgsinfo Running migrations: Rendering model states... DONE Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying admin.0002_logentry_remove_auto_add... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying auth.0007_alter_validators_add_error_messages... OK Applying manifests.0001_initial... OK Applying pkgsinfo.0001_initial... OK Applying process.0001_initial... OK Applying sessions.0001_initial... OK


#### Create the superuser

(mwa2_env)# python mwa2/manage.py createsuperuser Username (leave blank to use 'root'): root (or whatever you'd like) Email address: [email protected] Password: Password (again): Superuser created successfully.


#### Start the development web server

(mwa2_env)# cd mwa2 (mwa2_env)# gunicorn -c gunicorn.py munkiwebadmin.wsgi:application Starting gunicorn 20.1.0 Listening at: http://0.0.0.0:8000 (349470) Using worker: sync Booting worker with pid: 349471 Booting worker with pid: 349472 Booting worker with pid: 349473


#### Test the server
In a web browser, navigate to `http://[hostname_or_ip_of_the_rhel7_box]:8080`

### Optional/advanced

#### Configure LDAP authentication
Edit lines 167-191 of `mwa2/munkiwebadmin/settings.py`.  
See https://pythonhosted.org/django-auth-ldap/authentication.html#server-config for detailed documentation.  
Be sure to set `USE_LDAP` to `True`.

django ldap auth

USE_LDAP = True

LDAP authentication support

if USE_LDAP: import ldap from django_auth_ldap.config import LDAPSearch, PosixGroupType

# LDAP settings
AUTH_LDAP_SERVER_URI = "ldap://foo.example.com"
AUTH_LDAP_BIND_DN = ""
AUTH_LDAP_BIND_PASSWORD = ""
AUTH_LDAP_USER_SEARCH = LDAPSearch(
    "ou=People,o=ExampleCorp,c=US",
    ldap.SCOPE_SUBTREE, "(uid=%(user)s)")
AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
    "ou=Groups,o=ExampleCorp,c=US",
    ldap.SCOPE_SUBTREE, "(objectClass=posixGroup)")
AUTH_LDAP_GROUP_TYPE = PosixGroupType()
AUTH_LDAP_FIND_GROUP_PERMS = True
AUTH_LDAP_USER_ATTR_MAP = {"first_name": "givenName", 
                           "last_name": "sn",
                           "email": "mail"}
# Cache group memberships for an hour to minimize LDAP traffic
AUTH_LDAP_CACHE_GROUPS = True
AUTH_LDAP_GROUP_CACHE_TIMEOUT = 3600

#### Configuring MWA2 to start at boot (systemd-style)
This is not a guide to systemd or systemctl, and I am no systemctl expert, so there may be "better" approaches here:
##### Create a run script in the mwa2 directory

[root@vmmunki]# vi run_mwa2.sh

Be sure to replace the paths with the correct paths to your mwa2_env directory. Change the port number as desired/required:

#!/bin/sh

/path/to/mwa2_env/bin/python /path/to/mwa2_env/mwa2/manage.py runwsgiserver port=8080 host=0.0.0.0

Make sure it's executable:

[root@vmmunki]# chmod a+x run_mwa2.sh


##### Create a systemd service file

[root@vmmunki]# vi /etc/systemd/system/mwa2.service

Again, alter the path to the mwa2_env match your specific path:

[Unit] Description=MunkiWebAdmin2 Requires=httpd.service After=httpd.service

[Service] ExecStart=/path/to/mwa2_env/run_mwa2.sh Restart=always

[Install] WantedBy=multi-user.target

##### Tell systemd to load and run the mwa2.service

[root@vmmunki]# systemctl enable mwa2 Created symlink from /etc/systemd/system/multi-user.target.wants/mwa2.service to /etc/systemd/system/mwa2.service. [root@vmmunki]# systemctl start mwa2

MWA2 should be running shortly; you can check its status:

[root@vmmunki]# systemctl status mwa2 ● mwa2.service - MunkiWebAdmin2 Loaded: loaded (/etc/systemd/system/mwa2.service; enabled; vendor preset: disabled) Active: active (running) since Fri 2016-05-06 09:52:02 PDT; 33s ago Main PID: 11070 (run_mwa2.sh) CGroup: /system.slice/mwa2.service ├─11070 /path/to/mwa2_env/run_mwa2.sh └─11071 /path/to/mwa2_env/bin/python /path/to/mwa2_env/mwa2/manage.py runwsgiserver port=8080...

May 06 09:52:02 vmmunki systemd[1]: Started MunkiWebAdmin2. May 06 09:52:02 vmmunki systemd[1]: Starting MunkiWebAdmin2...


#### Configure Apache and mod_wsgi to serve the app

(notes by @dimaui)

I will just be covering the mwa2 specific content and not the complete Apache setup.    
This can probably be solved a lot nicer then the way I did it I am no python or apache expert.  
##### Copy the content here to your mwa2/munkiwebadmin/wsgi.py file and edit the paths.

import os import sys import site

MUNKIWEBADMIN_ENV_DIR = '/usr/local/mwa2_env/' MY_ENV_DIR2 = '/usr/local/mwa2_env/mwa2/'

Use site to load the site-packages directory of our virtualenv

site.addsitedir(os.path.join(MUNKIWEBADMIN_ENV_DIR, 'lib/python2.7/site-packages'))

Make sure we have the virtualenv and the Django app itself added to our path

sys.path.append(MUNKIWEBADMIN_ENV_DIR) sys.path.append(MY_ENV_DIR2) sys.path.append(os.path.join(MY_ENV_DIR2, 'munkiwebadmin'))

os.environ['DJANGO_SETTINGS_MODULE'] = 'munkiwebadmin.settings'

import django django.setup() import django.core.handlers.wsgi application = django.core.handlers.wsgi.WSGIHandler()

##### Create your apache config.    
Make sure to edit the paths and hostnames to suite your needs.
I use a Gunicorn process that gets proxied from the Apache server for the WSGI elements displayed on the MWA2 pages.

###### Debian 12 using Apache 2.4

#MWA2 PART <VirtualHost *:80> ServerName hostname.domain.com

ProxyPass /catalogs/static/ !
ProxyPass /manifests/static/ !
ProxyPass /munkiwebadmin/static/ !
ProxyPass /pkgsinfo/static/ !
ProxyPass / http://localhost:8000/

<Directory /usr/local/mwa2-env>
Require all granted
    Options -Indexes
</Directory>
```
⚠️ **GitHub.com Fallback** ⚠️