× К оглавлению На главную Об авторе

Дата и время публикации:    

Проблема и решение

1. Суть проблемы

Реализация локального сервера, замещающего репозитарий testPyPI, которые является публичным индексным репозитарием пакетов Python (Python Package Index, PyPI) и устраняющий угрозу разрушения реального индекса, исходя от pypi.org

Что также делает приватной разработку проектов Python, который может содержать один или несколько пакетов.

pypiserver предоставляет минимальную функциональность совместимую с pip или easy_install (легкая установка и развертывание).[3.1] Он реализован на базе проекта bottle [3.2] и работает с пакетами из регулярной директории. Поддерживает форматы пакетов wheel, eggs [3.3], и так называемой, конечной и зачастую бинарной сборки bdists [3.4], упакованной в бинарном формате одним из выбранных архиватором или упаковщика менеджера пакета Linux формата. Может использоваться вместе с PGP-сигнатурами и загружен либо с помощью утилитами pip, setuptools, twine, pypi-uploader или просто скопирован с scp [3.1].

2. Решение

2.1 Конфигурация, установка и запуск минимального сервера PyPI

Предоставляется пакетом pypiserver, который нужно установить и создать директорию локального репозитария, как показано в дампе 2.1.1

Дамп 2.1.1

$ pip install pypiserver
$ mkdir /home/$USER/yocto-poky/pypi-packages
...
  WARNING: The script pypi-server is installed in '/home/user/.local/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use —no-warn-script-location.
...

В данном случае, директорией локального репозитария /home/$USER/yocto-poky/pypi-packages находится на внешнем носителе информации, смонтированным в точке монтирования /home/$USER/yocto-poky

Далее, в ручную разбиваем директорию на поддиректории, где каждая из них соответствует названию проекта, дерево которого показано в дампе 2.1.2

Дамп 2.1.2

├── bar
│ └── bar-0.1.tar.gz
└── foo
    ├── Foo-1.0.tar.gz
    └── Foo-2.0.tar.gz

В котором показано дерево репозитария, состоящего из поддиректорий с нормализованными именами проекта, внутри которой находятся загружаемые файлы архивов. При этом, в случае наличия нескольких версий, имена файлов архивов должны иметь версии, подобно тому, какие имеют проект bar (одну версию — 0.1), а Foo (c версиями 1.0 и 2.0)

Каждая поддиректория должна иметь нормализованное имя проекта, в соответствии с требованиями PEP 503[3.7], что выражеается в том, что имя поддиректория проекта Foo должна быть приведена к foo, a Barbar [3.6]. PEP 503[3.7] так же требует наличие текстовой (индексной) страницы в HTML5, как показано в листинге 2.1.3 . При этом, это требование является обязательно, например, если вместо pypiserver будет использоваться apache2.

Листинг 2.1.4

<!DOCTYPE html>
<html>
  <body>
    <a href="/foo/">foo
    <a href="/bar/">bar
  </body>
</html>

В показанной структуре индексной страницы должны быть указаны линки от корня репозитария "/" с привязкой тэга к тексту и имеющий атрибут href, который ссылается на соответствующий проект согласно PEP 503 [3.7].

Поэтому теперь можем попробовать запустить pypiserver, например на сетевом порту 8080, т.к. на моей машине на порту 80 крутится Apache2 c собственном локальном хранилище Git-репозитариев [3.8] . Пробный запуск pypiserver показан в дампе 2.1.5

Дамп 2.1.5

/home/user/.local/bin/pypi-server -p 8080 /home/$USER/yocto-poky/pypi-packages
127.0.0.1 - - [24/Feb/2022 17:35:13] "GET / HTTP/1.1" 200 1007
127.0.0.1 - - [24/Feb/2022 17:35:13] "GET /favicon.ico HTTP/1.1" 404 711
127.0.0.1 - - [24/Feb/2022 17:35:37] "GET /packages/ HTTP/1.1" 200 333
127.0.0.1 - - [24/Feb/2022 17:35:43] "GET /simple/ HTTP/1.1" 200 241
127.0.0.1 - - [24/Feb/2022 17:35:47] "GET /packages/ HTTP/1.1" 200 333
127.0.0.1 - - [24/Feb/2022 17:36:43] "GET /packages/ HTTP/1.1" 200 333
127.0.0.1 - - [24/Feb/2022 17:36:43] "GET /favicon.ico HTTP/1.1" 404 711
...

Где показан удачный результат загрузки индексной страницы (/packages/) с кодом 200 и факт отказа при загрузки favicon.ico с кодом 404, отсутствие которого не влияет на функционирования pypi-packages, что и подтверждает нам динамически созданная страница для http://localhost:8080

Рисунок 2.1.6

2.2 Запуск в фоновом режиме под менеджера сеанса Systemd

Так как, в моем случае все было установлено в домашней директории, поэтому воспользовался функцию в systemd, реализующую долговременную службу (user_lingering) и позволяющей запускать службу до входа пользователя в систему [3.10]. Для чего, нужно сначало активировать эту функцию, как показано в дампе 2.2.1

Дамп 2.2.1

user@home2:~$ loginctl enable-linger user

При этом, если выполнить loginctl через sudo, то все остальные попытки запуска закончаться ошибкой, которая показан в дампе 2.2.2

Дамп 2.2.2

user@home2:~$ systemctl --user enable pypi-server.service
Failed to connect to bus: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined (consider using --machine=@.host --user to connect to bus of other user)

Потому что у самого пользователя не была активирована функция user_lingering в systemd [3.12]

После активации этой функции у пользователя, для запуска pypi-server нужно создать директорию ~/.config/systemd/user/ , если она не создана и поместить свой unit-файл с расширением .service

Пользовательский процесс systemd запускается сразу после первого входа пользователя в систему, и будет убит после завершения последнего сеанса пользователя. Иногда, может быть полезно запустить службу сразу после загрузки, и поддерживать процесс systemd запущенным даже после завершения последнего сеанса пользователя, например, чтобы некоторый пользовательский процесс работал без какой-либо открытой сессии. Для этой цели используются долговременные службы, которые запускаются из директории ~/.config/systemd/user/ и в unit-файле, как показано в дампе 2.2.3

Дамп 2.2.3

# саt ~/.config/systemd/user/pypi-server.service

[Unit]
Description=pypiserver daemon

[Service]
ExecStart=/home/user/.local/bin/pypi-server -p 8080 --log-file /home/user/.local/log/pypi-server.log /home/user/yocto-poky/pypi-packages
ExecStop=/bin/kill -TERM $MAINPID
ExecReload=/bin/kill -HUP $MAINPID
Restart=always

WorkingDirectory=/home/user/yocto-poky/pypi-packages

[Install]
WantedBy=default.target

Теперь нужно, активировать функцию и попробовать запустить сервис, как показано в дампе 2.2.4

Дамп 2.2.4

 
$ systemctl --user enable pypi-server.service
Created symlink /home/user/.config/systemd/user/default.target.wants/pypi-server.service → /home/user/.config/systemd/user/pypi-server.service.  
...
user@home2:~$ systemctl --user daemon-reload
...
user@home2:~$ systemctl --user start pypi-server
user@home2:~$ systemctl --user status pypi-server
● pypi-server.service - pypiserver daemon
     Loaded: loaded (/home/user/.config/systemd/user/pypi-server.service; enabled; vendor preset: enabled)
     Active: active (running) since Fri 2022-02-25 10:19:21 MSK; 5s ago
   Main PID: 6741 (pypi-server)
      Tasks: 1 (limit: 16615)
     Memory: 17.6M
        CPU: 201ms
     CGroup: /user.slice/user-1000.slice/user@1000.service/app.slice/pypi-server.service
             └─6741 /usr/bin/python3 /home/user/.local/bin/pypi-server -p 8080 --log-file /home/user/.local/log/pypi-server.log /home/user/yocto-poky/pypi-packages

фев 25 10:19:21 home2 systemd[946]: Started pypiserver daemon.

В случае внесения изменения в файл pypi-server может потребоваться выполнить systemctl с --user daemon-reload, как показано выше в дампе 2.2.4

Для отключения функции поддержки долговременной службы выполните команду из дампа 2.2.5

Дамп 2.2.5

 
$ systemctl --user stop pypi-server.service
$ systemctl --user disable pypi-server.service
$ loginctl disable-linger

Соответственно, перед этим мне нужно было остановить службу pypi-server и деактивировать. А уже потом отключить поддежку запуска долговременных служб у пользователя.

2.3 Поддержка процедуры аутентификации

Для ее включения, мне понадобилось установить модуль passlib, который поддерживает разбор, требуемый также при запуске приложения wsgi в Apaches, файла аутентификации формата htpasswd, как показано в дампе 2.3.1

Дамп 2.3.1

$ pip install passlib

Соответственно, после чего добавил пользователя pypisrv, который не зарегистрирован в системе, как показано в дампе 2.3.2

Дамп 2.3.2

$ htpasswd -sc /home/$USER/yocto-poky/pypi-packages/.htpasswd pypisrv

После чего, мне оставалось лишь сделать правки в файл ~/.config/systemd/user/pypi-server.service, как показано в дампе 2.3.3

Дамп 2.3.3

# саt ~/.config/systemd/user/pypi-server.service

[Unit]
Description=pypiserver daemon

[Service]
ExecStart=/home/user/.local/bin/pypi-server -p 8080 -a update,download -P /home/$USER/yocto-poky/pypi-packages/.htpasswd --log-file /home/user/.local/log/pypi-server.log /home/user/yocto-poky/pypi-packages

ExecStop=/bin/kill -TERM $MAINPID
ExecReload=/bin/kill -HUP $MAINPID
Restart=always

WorkingDirectory=/home/user/yocto-poky/pypi-packages

[Install]
WantedBy=default.target

В результате, мной были добавлена опция -a (--authenticate) c установленными действиями для аутентификации, такие как updatе или download, и вместе с ней опция -P , где искать файл с паролями.

Далее, мне осталось лишь перезапустить сервиc pypi-sever, как показано в дампе 2.3.4

Дамп 2.3.4

~$ systemctl --user daemon-reload
~$ systemctl --user restart pypi-server.service
~$ systemctl --user status pypi-server.service
● pypi-server.service - pypiserver daemon
     Loaded: loaded (/home/user/.config/systemd/user/pypi-server.service; enabled; vendor preset: enabled)
     Active: active (running) since Sun 2022-02-27 21:58:08 MSK; 4s ago
   Main PID: 20479 (pypi-server)
      Tasks: 1 (limit: 16615)
     Memory: 19.1M
        CPU: 261ms
     CGroup: /user.slice/user-1000.slice/user@1000.service/app.slice/pypi-server.service
             └─20479 /usr/bin/python3 /home/user/.local/bin/pypi-server -p 8080 -a update,download -P /home/user/yocto-poky/pypi-packages/.htpasswd --log-file /home/user/.local/log/pypi-server.log /home/user/yo> 

После чего, установил разработанный мной пакет shellenv-package-rjaan, как показано в дампе 2.3.5

Дамп 2.3.5

~$ pip install --index-url http://localhost:8080/simple/ shellenv-package-rjaan
Defaulting to user installation because normal site-packages is not writeable
Looking in indexes: http://localhost:8080/simple/
warning: missing-index-doctype

× The package index page being used does not have a proper HTML doctype declaration.
╰─> Problematic URL: http://localhost:8080/simple/shellenv-package-rjaan/

note: This is an issue with the page at the URL mentioned above.
hint: You might need to reach out to the owner of that package index, to get this fixed. See https://github.com/pypa/pip/issues/10825 for context.
Collecting shellenv-package-rjaan
User for localhost:8080: pypisrv
Password: 
  Downloading http://localhost:8080/packages/myprog/shellenv-package-rjaan-0.1.tar.gz (2.8 kB)
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... done
Building wheels for collected packages: shellenv-package-rjaan
  Building wheel for shellenv-package-rjaan (pyproject.toml) ... done
  Created wheel for shellenv-package-rjaan: filename=shellenv_package_rjaan-0.1-py3-none-any.whl size=3539 sha256=7441388ce993b19cd95b0246c7c0b0d53a83517f38ac4b63fdc6e83dc191a28e
  Stored in directory: /home/user/.cache/pip/wheels/a7/40/d7/e11b7c490a75e5e7decde841885bd8e03e85b615e4d551eeb4
Successfully built shellenv-package-rjaan
Installing collected packages: shellenv-package-rjaan
Successfully installed shellenv-package-rjaan-0.1

При этом, для загрузки пакета мне понадобилось ввести пару значений аутентификационных данных (выделено жирным), состоящие из имени пользователя – pypisrv и его пароля, установленные ранее в дампе 2.3.2

2.4 Запуск в apache2

В моем случае, речь шла об начальной интеграции хранилища Git-репозитариев, настроенного ранее [3.10], и индексируемого репозитария пакетов Python (Python package index) на уровне разграничения полномочий, потому что все процессы с сайтами в моей конфигурации порождаются от имени пользователя git, а это значит все ранее устанавливаемые которого пораждаются apache2

Поэтому мне понадобилось установить те же самые пакеты Python у пользователя git, что устанавливались ранее во время разворачивания pypi-server, как это показано в дампе 2.4.1

Дамп 2.4.1

 
$ sudo -u git pip install pypiserver
[sudo] пароль для user:                                                         
Collecting pypiserver
  Downloading pypiserver-1.4.2-py2.py3-none-any.whl (77 kB)
     |████████████████████████████████| 77 kB 711 kB/s 
Installing collected packages: pypiserver
  WARNING: The script pypi-server is installed in '/home/git/.local/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed pypiserver-1.4.2

$ sudo -u git pip install passlib
Collecting passlib
  Downloading passlib-1.7.4-py2.py3-none-any.whl (525 kB)
     |████████████████████████████████| 525 kB 2.4 MB/s 
Installing collected packages: passlib
Successfully installed passlib-1.7.4

$ sudo -u git mkdir -p /home/git/pypisrv/wsgi

Для использования Apache2 в связке с pypiserver предпочтительно использовать mod_wsgi [3.1], как предлагается в проекте Buttle [3.13]. Для чего, нужно удостверится, что установлен соответсвующий пакет. Так для Debian-11 таким пакетом является libapache2-mod-wsgi-py3, проверка наличия и установка которого показана в дампе 2.4.2

Дамп 2.4.2

 
$ apt search libapache2-mod-wsgi-py3
Сортировка… Готово
Полнотекстовый поиск… Готово
libapache2-mod-wsgi-py3/stable 4.7.1-3+b1 i386
  Python 3 WSGI adapter module for Apache

$ sudo apt install libapache2-mod-wsgi-py3  
[sudo] пароль для user: 
Чтение списков пакетов… Готово
Построение дерева зависимостей… Готово
Чтение информации о состоянии… Готово         
Следующие НОВЫЕ пакеты будут установлены:
  libapache2-mod-wsgi-py3
...
apache2_invoke: Enable module wsgi

Далее, в директории /etc/apache2, как показано в дампе 2.4.3, настраиваем альтернативные порты 8443 и 8080

Дамп 2.4.3

 
...
Listen 80
Listen 8080

<IfModule ssl_module>
        Listen 443
        Listen 8443
</IfModule>

<IfModule mod_gnutls.c>
        Listen 443
        Listen 8443
</IfModule>
...

На основании уже имеющегося файла 000-default.conf в директории /etc/apache2/sites-available создал 001-default.conf под порт 8080 и привел, как показано в дампе 2.4.4

Дамп 2.4.4

 
sudoedit /etc/apache2/sites-available/001-default.conf
...
<VirtualHost *:8080>
        # The ServerName directive sets the request scheme, hostname and port that
        # the server uses to identify itself. This is used when creating
        # redirection URLs. In the context of virtual hosts, the ServerName
        # specifies what hostname must appear in the request's Host: header to
        # match this virtual host. For the default virtual host (this file) this
        # value is not decisive as it is used as a last resort host regardless.
        # However, you must set it for any further virtual host explicitly.
        #ServerName www.example.com

        ServerAdmin  root@localhost
        DocumentRoot /home/git/pypisrv
        <Directory /home/git/pypisrv>
              Require all granted
        </Directory>

        # WSGI Settings
        WSGIScriptAlias   /     /home/git/pypisrv/wsgi/pypiserver.wsgi
        WSGIDaemonProcess       pypisrv user=git group=git umask=0007 \
                                processes=1 threads=5 maximum-requests=500 \
                                display-name=wsgi-pypisrv inactivity-timeout=300
        WSGIProcessGroup        pypisrv
        # Required for authentication (https://github.com/pypiserver/pypiserver/issues/288)
        WSGIPassAuthorization   On

        <Directory /home/git/pypisrv/wsgi>
           <Files pypiserver.wsgi>
              Require all granted
           </Files>
        </Directory>

        # Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
        # error, crit, alert, emerg.
        # It is also possible to configure the loglevel for particular
        # modules, e.g.
        #LogLevel info ssl:warn

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

        # For most configuration files from conf-available/, which are
        # enabled or disabled at a global level, it is possible to
        # include a line for only one particular virtual host. For example the
        # following line enables the CGI configuration for this host only
        # after it has been globally disabled with "a2disconf".
        #Include conf-available/serve-cgi-bin.conf
</VirtualHost>

Как показано в листинге 2.4.5, конструктором pypiserver:app() запускается pypiserver в bottle-приложении со следующей ключевые значения конфигурации:

Перезапускаем сервер, как показано в дампе 2.4.6

Дамп 2.4.6

$ sudo service apache2 reload
$ sudo service apache2 restart
$ sudo service apache2 status
● apache2.service - The Apache HTTP Server
     Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
     Active: active (running) since Mon 2022-02-28 17:25:59 MSK; 3min 0s ago
       Docs: https://httpd.apache.org/docs/2.4/
    Process: 21212 ExecStart=/usr/sbin/apachectl start (code=exited, status=0/SUCCESS)
   Main PID: 21216 (apache2)
      Tasks: 64 (limit: 16615)
     Memory: 53.3M
        CPU: 699ms
     CGroup: /system.slice/apache2.service
             ├─21216 /usr/sbin/apache2 -k start
             ├─21217 /usr/sbin/apache2 -k start
             ├─21218 wsgi-pypisrv      -k start
             ├─21219 /usr/sbin/apache2 -k start
             └─21220 /usr/sbin/apache2 -k start

фев 28 17:25:59 home2 systemd[1]: Starting The Apache HTTP Server...
фев 28 17:25:59 home2 systemd[1]: Started The Apache HTTP Server.

После чего,, мне осталось лишь настроить доступ Apach-пользователя pypisrv к только что запущенному виртуальном узлу, как это делалось ранее и показано в дампе 2.4.7

Дамп 2.4.7

$ htpasswd -sc /home/git/pypi-packages/.htpasswd pypisrv

Теперь, мне лишь осталось обеспечить доступ по HTTPS и альтернативному порту 8443, т.к. родной порт 443 планирую использовать в дальнейшем с виртуальным узлом, выделенный для обслуживания хранилища Git-репозитариев.

Поэтому переименовал файл 001-default.conf в 002-default.conf в директории /etc/apache2/sites-available и привел к виду, как показано в листинге 2.4.8

Дамп 2.4.8

<VirtualHost *:8443>
        # The ServerName directive sets the request scheme, hostname and port that
        # the server uses to identify itself. This is used when creating
        # redirection URLs. In the context of virtual hosts, the ServerName
        # specifies what hostname must appear in the request's Host: header to
        # match this virtual host. For the default virtual host (this file) this
        # value is not decisive as it is used as a last resort host regardless.
        # However, you must set it for any further virtual host explicitly.
        #ServerName www.example.com

        ServerAdmin  root@localhost
        DocumentRoot /home/git/pypisrv
        <Directory /home/git/pypisrv>
              Require all granted
        </Directory>

        # WSGI Settings
        WSGIScriptAlias   /     /home/git/pypisrv/wsgi/pypiserver.wsgi
        #WSGIDaemonProcess       pypisrv user=git group=git umask=0007 \
        #                        processes=1 threads=5 maximum-requests=500 \
        #                        display-name=wsgi-pypisrv inactivity-timeout=300
        WSGIProcessGroup        pypisrv
        # Required for authentication (https://github.com/pypiserver/pypiserver/issues/288)
        WSGIPassAuthorization   On

        <Directory /home/git/pypisrv/wsgi>
           <Files pypiserver.wsgi>
              Require all granted
           </Files>
        </Directory>
                 
        #   SSL Engine Switch: 
        #   Enable/Disable SSL for this virtual host.
        SSLEngine on

        #   A self-signed (snakeoil) certificate can be created by installing
        #   the ssl-cert package. See
        #   /usr/share/doc/apache2/README.Debian.gz for more info.
        #   If both key and certificate are stored in the same file, only the
        #   SSLCertificateFile directive is needed.
        SSLCertificateFile    /etc/ssl/certs/ssl-cert-snakeoil.pem
        SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key

        #   SSL Protocol Adjustments:
        #   The safe and default but still SSL/TLS standard compliant shutdown
        #   approach is that mod_ssl sends the close notify alert but doesn't wait for
        #   the close notify alert from client. When you need a different shutdown
        #   approach you can use one of the following variables:
        #   o ssl-unclean-shutdown:
        #        This forces an unclean shutdown when the connection is closed, i.e. no
        #        SSL close notify alert is send or allowed to received.  This violates
        #        the SSL/TLS standard but is needed for some brain-dead browsers. Use
        #        this when you receive I/O errors because of the standard approach where
        #        mod_ssl sends the close notify alert.
        #   o ssl-accurate-shutdown:
        #        This forces an accurate shutdown when the connection is closed, i.e. a
        #        SSL close notify alert is send and mod_ssl waits for the close notify
        #        alert of the client. This is 100% SSL/TLS standard compliant, but in
        #        practice often causes hanging connections with brain-dead browsers. Use
        #        this only for browsers where you know that their SSL implementation
        #        works correctly.
        #   Notice: Most problems of broken clients are also related to the HTTP
        #   keep-alive facility, so you usually additionally want to disable
        #   keep-alive for those clients, too. Use variable "nokeepalive" for this.
        #   Similarly, one has to force some clients to use HTTP/1.0 to workaround
        #   their broken HTTP/1.1 implementation. Use variables "downgrade-1.0" and
        #   "force-response-1.0" for this.
        BrowserMatch "MSIE [2-6]" \
                        nokeepalive ssl-unclean-shutdown \
                        downgrade-1.0 force-response-1.0
        # MSIE 7 and newer should be able to use keepalive
        BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
        
        # allow user who has a certificate to access a particular URL if user presented it.   
        # <Location />
        #    SSLRequireSSL On
        #    SSLVerifyClient optional
        #    SSLVerifyDepth 1
        #    SSLOptions +StdEnvVars +StrictRequire
        # </Location>

        #   SSL Engine Options:
        #   Set various options for the SSL engine.
        #   o FakeBasicAuth:
        #        Translate the client X.509 into a Basic Authorisation.  This means that
        #        the standard Auth/DBMAuth methods can be used for access control.  The
        #        user name is the `one line' version of the client's X.509 certificate.
        #        Note that no password is obtained from the user. Every entry in the user
        #        file needs this password: `xxj31ZMTZzkVA'.
        #   o ExportCertData:
        #        This exports two additional environment variables: SSL_CLIENT_CERT and
        #        SSL_SERVER_CERT. These contain the PEM-encoded certificates of the
        #        server (always existing) and the client (only existing when client
        #        authentication is used). This can be used to import the certificates
        #        into CGI scripts.
        #   o StdEnvVars:
        #        This exports the standard SSL/TLS related `SSL_*' environment variables.
        #        Per default this exportation is switched off for performance reasons,
        #        because the extraction step is an expensive operation and is usually
        #        useless for serving static content. So one usually enables the
        #        exportation for CGI and SSI requests only.
        #   o OptRenegotiate:
        #        This enables optimized SSL connection renegotiation handling when SSL
        #        directives are used in per-directory context.
        SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
</VirtualHost>

При этом, строчки для WSGIDaemonProcess были закоментированы, т.к. является достяжимой к WSGIDaemonProcess из конфигурации виртуального узла для порта 8080

После чего, нужно задействовать готовый профиль default-ssl, как показано в дампе 2.4.9

Дамп 2.4.9

 sudo a2ensite 002-default.conf
 sudo systemctl restart apache2
 sudo systemctl reload apache2

В результате получил картинку, которая показана на рисунке 2.4.10

Рисунок 2.4.10

2.5 Установка пакетов

После чего, смог сделать разработку более безопасной своего первого и маленького проекта shellenv, реализующий функциональность SHELL-команды env(1), которая относится к архаичной системе (legacy system) и выполняемой интерпретатором команд dash, sh, bash, ksh или более свежим их аналогом zsh

Далее, полученные файлы закладываем в локальный индексный репозитарий пакетов Python, который находится в директории /home/git/pypisrv/, как показано в дампе 2.5.1

Дамп 2.5.1

~ /home/git/pypisrv$ exa --tree  
.
├── shellenv/
  └── shellenv-package-rjaan-0.1.tar.gz

После чего, можно выполнить установку пакета shellenv, как показано в дампе 2.5.2

Дамп 2.5.2

pip install --upgrade -U shellenv-package-rjaan --extra-index-url http://localhost:8080/simple

При этом, если использовать --index-url, то возникает ошибка разрешения зависимостей.

Для включения загрузки и установки пакетов с использованием механизма аутентификации в файле /home/git/pypisrv/wsgi/pypiserver.wsgi нужно добавить соответствующую строчку (выделенную жирным) в листинге 2.5.3

Дамп 2.5.3

#!/usr/bin/env python3
# An example pypiserver-wsgi.py for use with apache2 and mod_wsgi, edit as necessary.
#
# apache virtualhost configuration for mod_wsgi daemon mode:
# Alias /robots.txt /srv/yoursite/htdocs/robots.txt
# WSGIPassAuthorization On
# WSGIScriptAlias / /srv/yoursite/cfg/pypiserver.wsgi
# WSGIDaemonProcess pypisrv user=pypisrv group=pypisrv processes=1 threads=5 maximum-requests=500 umask=0007 display-name=wsgi-pypisrv inactivity-timeout=300
# WSGIProcessGroup pypisrv 

USER="git"
PACKAGES = "/home/"+USER+"/pypisrv/"
HTPASSWD = PACKAGES+".htpasswd"

import pypiserver

conf = pypiserver.default_config (
        root= PACKAGES,
        redirect_to_fallback=False,
        password_file=HTPASSWD,
        auther=pam.authenticate,
        overwrite=True )

application = pypiserver.app(**conf)

Добавленная мной строчка auther=pam.authenticate, нужна для реализации поддержки аутентификации провойдеров узлов децентрализованной беспроводной сети (ad hoc authentification providers)[3.19], которая основывается на файловой базы данных учетных записей в среде Linux и подобных Unix-систем.

При этом, нужно доставить пакет pam для пользователя git, от имени которого запускается apache2 и соответственно, как показано в дампе 2.5.4

Дамп 2.5.4

$ sudo -u git pip install --upgrade pam
Requirement already satisfied: pam in /home/git/.local/lib/python3.9/site-packages (0.2.0)
Collecting pam
  Using cached pam-0.2.0-py3-none-any.whl (976 bytes)
  Downloading pam-0.1.4.tar.gz (2.6 kB)
Requirement already satisfied: python-pam in /home/git/.local/lib/python3.9/site-packages (from pam) (1.8.4)

После чего, можно попробовать установить пакет shellenv, как показано ниже.

2.6 Совместное использование Git и индексного репозитраия пакетов Python

Выполнить клонирование пакета shellenv из локального git-репозитария, как показано в дампе 2.6.1

Дамп 2.6.1

$ LANG=C git clone git://localhost/python-shellenv.git
Cloning into 'python-shellenv'...
remote: Enumerating objects: 28, done.
remote: Counting objects: 100% (28/28), done.
remote: Compressing objects: 100% (22/22), done.
Receiving objects: 100% (28/28), 4.73 KiB | 4.73 MiB/s, done.
remote: Total 28 (delta 5), reused 0 (delta 0), pack-reused 0
Resolving deltas: 100% (5/5), done.

Перейти в python-shellenv и выполнить сборку пакета, после чего пакет поместить, как показано в дампе 2.5.1

3. Библиография

3.1 pypiserver - minimal PyPI server for use with pip/easy_install

3.2 Bottle: Python Web Framework

3.3 PyPA. Wheel vs Egg

3.4 Python. Creating Built Distributions

3.5 Монтирования партиций (носителей информации) по ее метке.

3.6 PyPA. Hosting your own simple repository

3.7 Python. PEP 503 -- Simple Repository API

3.8 Как разворачивать свой собственное (локальное) хранилище Git репозитариев

3.9 provide systemd service template for pypiserver #137

3.10 ArchLinux. Systemd (Русский)/User (Русский)

3.12 0.0.35: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not defined

3.13 bottle’s documentation on the Apache’s module MOD_WSGI

3.14 Список файлов пакета libapache2-mod-wsgi-py3 в bullseye для архитектуры amd64

3.15 wolfg, wolfg1969 оn gist.github.com

3.16 pypiserver on GitHub

3.17 How to setup apache fo multi user

3.18 How to deploy own git server

3.19 Беспроводная ad-hoc-сеть

Сайт разработан в соответствии с рекомендациями консорциума W3C для языка разметки HTML5.

Об авторе можно прочитать здесь.

Copyright © 2015-2019 Андрей Ржавсков