Debian, Dojo, Django, Python

Делюсь опытом в описанных технологиях. Блог в первую очередь выполняет роль памяток для меня самого.

Показаны сообщения с ярлыком ошибка. Показать все сообщения
Показаны сообщения с ярлыком ошибка. Показать все сообщения

Debian Buster, SecureBoot и Nvidia RTX 2070

Условия задачи

Дано:

  • Ошибка Xorg в логах: May 7 16:21:42 darktower kernel: [ 5.572986] Lockdown: ioperm is restricted; see https://wiki.debian.org/SecureBoot
  • Debian 10 Booster с подключенными репозиториями non-free и contrib.
  • Права root
  • Видеокарта NVidia RTX 2070
  • Компьютер с включенной в настройках материнской платы опцией SecureBoot (EFI)

Проблема в том, что в ряде случаев видеокарта может не запускаться, потому что драйверы не подписаны. Для подписания драйверов следует выполнить действия, описанные в Wiki Debian / SecureBoot.

В моём случае пришлось выполнить следующую последовательность действий:

Установка драйвера Nvidia, исходных кодов ядра и mokutil

Установка драйвера
apt-get update
apt-get install nvidia-driver nvidia-xconfig linux-headers-amd64 mokutil
Пакет Предназначение
nvidia-driver Проприетарный драйвер Nvidia с поддержкой нужных моделей видеокарт.
nvidia-xconfig Утилита конфигурирования параметров Xorg для поддержки им нужных драйверов.
linux-headers-amd64 Исходные коды установленного ядра.
mokutil Утилита для работы с ключами EFI

Генерация ключа EFI, его установка и подписывание драйверов.

Теперь действуем ровно так, как написано в руководстве Debian'а:

Генерация ключа и подписывание драйверов
# Генерация ключей и импорт в EFI
cd  /root
openssl req -new -x509 -newkey rsa:2048 -keyout MOK.priv -outform DER -out MOK.der -nodes -days 36500 -subj "/CN=NVidia RTX 2070 key/"
mokutil --import MOK.der

# Подписывание драйверов Nvidia
cd /lib/modules/4.19.0-8-amd64/updates/dkms/
/usr/lib/linux-kbuild-4.19/scripts/sign-file sha256 /root/MOK.priv /root/MOK.der nvidia-current-drm.ko 
/usr/lib/linux-kbuild-4.19/scripts/sign-file sha256 /root/MOK.priv /root/MOK.der nvidia-current.ko 
/usr/lib/linux-kbuild-4.19/scripts/sign-file sha256 /root/MOK.priv /root/MOK.der nvidia-current-modeset.ko 
/usr/lib/linux-kbuild-4.19/scripts/sign-file sha256 /root/MOK.priv /root/MOK.der nvidia-current-uvm.ko 

# Перенастройка Xorg под nvidia
cd /etc/X11
rm xorg.conf
nvidia-xconfig

Следует обратить внимание на путь, в котором расположены исходные модули ядра nvidia и скрипт для подписывания драйверов - они могут быть другими.

Перезагрузка

При перезагруке EFI выдаст сообщение, что появился запрос на установку собственного ключа цифровой подписи. Принимаем этот ключ и устанавливаем. После этого компьютер должен перезагрузиться и запустить установленный Linux, используя подписанные данным ключом драйверы. После этого запустится Xorg и всё будет нормально работать.

Автоматизация подписывания ключей.

Можно автоматизировать процесс по максимуму, если ручной выбор исходников ядра переключить на работу с результатами команды uname -r и поместить всё в файл скрипта:

/root/sign_nvidia_drivers.sh
#!/bin/sh

SIGN=/usr/lib/linux-kbuild-4.19/scripts/sign-file
MOK=/root/MOK.priv
DER=/root/MOK.der

cd /lib/modules/$(uname -r)/updates/dkms/

$SIGN sha256 $MOK $DER nvidia-current-drm.ko
$SIGN sha256 $MOK $DER nvidia-current.ko
$SIGN sha256 $MOK $DER nvidia-current-modeset.ko
$SIGN sha256 $MOK $DER nvidia-current-uvm.ko

Его нужно запускать всякий раз при обновлении драйвера Nvidia или ядра.

Ошибка "memmove does not exist on this platform"

Который раз вижу вот эту ошибку:

extensions/expat/lib/xmlparse.c:75:2: error: #error memmove does not exist on this platform, nor is a substitute available

Решение очень легко гуглится на StackOverflow, но для себя я решил сохранить, чтобы далеко не ходить. Проблема заключается в том, что в одном из заголовочных файлов Python 2.7 не определена константа HAVE_MEMMOVE

Решение

  • Открыть файл /usr/include/python2.7/pyconfig.h
  • Добавить в его конец строку

    #define HAVE_MEMMOVE 1

Послесловие: хватит уже пользоваться Python 2.7, Гвидо не для того старался с тройкой.

str object has no attribute _meta

Досадная ошибка, с которой пришлось столкнуться, вынесена в название статьи. Потратил два часа на поиски, просмотрел все файлы по нескольку раз - и ничего. Сегодня с утра (а утро вечера мудренее) обнаружил причину.

Было:
class UserChangeForm(forms.ModelForm):

'''
Форма для обновления данных пользователей. Нужна только для того, чтобы не
видеть постоянных ошибок "Не заполнено поле password" при обновлении данных
пользователя.
'''
password = ReadOnlyPasswordHashField(
    widget=forms.PasswordInput,
    required=False
)

def clean_password(self):
    return self.initial['password']

def save(self, commit=True):
    user = super(UserChangeForm, self).save(commit=False)
    password = self.cleaned_data["password"]
    if password:
        user.set_password(password)
    if commit:
        user.save()
    return user

class Meta:
    model = get_user_model()
    fields = ('email')
Стало:
class UserChangeForm(forms.ModelForm):

'''
Форма для обновления данных пользователей. Нужна только для того, чтобы не
видеть постоянных ошибок "Не заполнено поле password" при обновлении данных
пользователя.
'''
password = ReadOnlyPasswordHashField(
    widget=forms.PasswordInput,
    required=False
)

def clean_password(self):
    return self.initial['password']

def save(self, commit=True):
    user = super(UserChangeForm, self).save(commit=False)
    password = self.cleaned_data["password"]
    if password:
        user.set_password(password)
    if commit:
        user.save()
    return user

class Meta:
    model = get_user_model()
    fields = ['email', ]
СУТЬ:

Если делаете перечисление полей в виде кортежа, после последнего элемента обязательно должна быть поставлена запятая. А лучше перечисляйте в квадратных скобках, как список - тогда точно не ошибётесь. Грабли, на которые наступают все новички, и я в том числе тоже.

Потенциальная возможность ошибки:
class Meta:
    model = get_user_model()
    fields = ('email',)
Ошибки исключены
class Meta:
    model = get_user_model()
    fields = ['email']

Ошибка при запуске Eclipse Luna в Debian

Проблема

Я на работе окончательно переехал на Debian. После двух дней ненависти к Ubuntu понял, что лучше иметь старые проверенные пакеты, чем новые и постоянно глючащие. Как обычно, после установки системы поставил JRE:

apt-get update && apt-get install openjdk-7-jre -y

Скачал и распаковал последнюю стабильную версию Eclipse с официального сайта. Попробовал запустить:

./eclipse

Получил кучу ошибок, среди которых была такая: # C [libgdk-x11-2.0.so.0+0x5173f] gdk_display_open+0x3f.

Решение

Решение оказалось на редкость простым. Нужно импортировать в окружение переменную SWT_GTK3=0, тогда всё будет работать. Прописал в конце файла /etc/profile:

export SWT_GTK3=0

Чтобы не перезагружать систему, сделал то же самое для текущего пользователя, т.е. выполнил указанную выше команду. Всё работает!

Django и $resource

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

Решил использовать для реализации RESTful API своего приложения такой модуль Angular, как angular-resource. Проблем с установной и подключением, как обычно, не было. Создал свой сервис:

(function (A, U) { //U === undefined
    "use strict";
        
    A.module('DesktopApplication').factory('Category', function ($resource) {
        var instance = {
            selectedRow: U, //Используется в моём проекте для обмена данными между контроллерами,
                            //не является обязательным элементом
            resource: $resource('/category/rows/:id', {id: '@id'})
        };
        return instance;        
    });
}(this.angular));

Казалось бы, всё должно работать. И ведь правда, вот такое работает (GET-запрос на получение данных):

//Где-то в коде, использующем сервис Category
Category.resource.query(function (items){
    $scope.rows = items;
});

А вот такое уже нет:

//Чуть ниже
Category.save({'id': 4, 'name': 'Username'}, function (result) {
    $scope.success = result.success;
});

Проблема оказалась в том, что даже явно указав слэш в конце строки ресурса, я получил POST-запросы, идущие к адресам без слэша, и Django такие запросы тут же банит. Начался поиск и чтение StackOverflow.

Решение

Решение оказалось довольно простым. Нужно указать в настройках приложения, что удалять концевой слэш для URL в AJAX-запросах не надо (а по-умолчанию включено). Кроме того, для корректной работы запросов методом PUT и DELETE нужно дополнительно конфигурировать $http. Иначе декоратор @csrf_protect из комплекта Django будет резать такие запросы. С учётом вышесказанного, скрипт настройки приложения стал выглядеть так (для сокращения размера выброшены прочие модули, которые я на самом деле использую в своём проекте):

(function(A) {
    "use strict";
    A.module('DesktopApplication', [ 'ngCookies', 'ngResource')
     .config(function ($interpolateProvider, $resourceProvider) {
         $interpolateProvider.startSymbol('{$');
         $interpolateProvider.endSymbol('$}');
         $resourceProvider.defaults.stripTrailingSlashes = false;
      })
     .run(function ($http, $cookies) {
          $http.defaults.headers.common['X-CSRFToken'] = $cookies.csrftoken;
          $http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;
          $http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
     });
}(this.angular, this.jQuery));

Non Unicode character at position...

Введение

Как я уже писал ранее, моя компания использует множество проектов, написанных на Python. В качестве платформы для некоторых продуктов используется M3, построенная на основе популярного фреймворка Django. При первоначальной установке проектов на боевые сервера я столкнулся с тем, что при загрузке на сервер файлов, в имени которых встречается кириллица, система выдаёт невнятные сообщения. Оказалось, что проблема заключается в неправильной работе Python с кодировками, в которых хранятся имена файлов. В частности, от этого постоянно падали PIL и Pillow, а в некоторые разделы файлы не загружались вовсе.

В поисках решения

Первым делом я отправился в гугл, конечно же. Введя в поиск заголовок этой статьи, я наткнулся на кучу статей, в большинстве которых предлагались следующие варианты решения проблемы:

  • Использовать в коде явное преобразование строк из одной кодировки в другую с помощью встроенных функций языка либо сторонних пакетов.
  • Установить в систему нужные локали.
  • Прописать настройки в конфигах Django.
  • Перейти с этого вашего Python'а на PHP или Ruby On Rails.

Как выяснилось, ни один из этих путей не решает возникшую проблему, однако, второй пункт показался мне достаточно здравым.

Установка в систему нужных локалей.

При установке Debian 7 предлагается выбрать язык системы и кодировку по умолчанию. Если Вы указали свою национальную кодировку (уверен, меня читают не только жители России, но и других стран СНГ), можете этот пункт пропустить. Если же нет, то приступим к установке:

Первым делом следует войти в систему от имени root и выполнить команду по установке пакета управления локалями:

apt-get install locales

После установки этого пакета становится доступна следующая команда:

 dpkg-reconfigure locales

Откроется окно, в котором нужно с помощью пробела отметить локали, которые следует держать в системе (можно выбрать вариант "Все локали", но я не рекомендую - чем меньше в системе лишнего, тем лучше). Я оставил там две локали: en_US.UTF-8 и ru_RU.UTF-8.

После нажатия кнопки OK будет предложено выбрать локаль по-умолчанию. Я использую ru_RU.UTF-8.

В самом конце система приступит к генерации недостающих локалей и их установке в систему.

Настройка окружения для работы Python

Как я писал в одной из статей, для запуска проектов на Python 2.x лучшим выбором является виртуальное окружение, созданное с помощью virtualenv, в которое установлен Gunicorn. При этом управление всем приложением осуществляется с помощью Supervisor'а. Здесь же сразу перейдём к делу.

Переходим в каталог настроек приложений Supervisor'а:

cd /etc/supervisor/conf.d/

Открываем файл настроек нашего приложения и приводим его к следующему виду:

[program:project]
environment=PROJECT_CONFIG_PATH="/var/www/project/conf/",DJANGO_SETTINGS_MODULE="project.settings",PYTHONIOENCODING="UTF-8",LANG="ru_RU.UTF-8",LC_ALL="ru_RU.UTF-8",LC_LANG="ru_RU.UTF-8"
command=/var/www/.virtualenvs/project/bin/gunicorn_django -c /var/www/project/conf/gunicorn.conf.py

user=www-data
group=www-data

daemon=false
debug=false

autostart=true
autorestart=true

redirect_stderr=true
stdout_logfile=/var/www/project/log/supervisor.log

Самая важная строка здесь - та, в которой задаётся значение параметра environment. Именно там указывается, какие локали использовать Python'у для работы с файлами, языком и т.д. Именно эта небольшая строка предотвращает ошибки вида "Non Unicode character at position..." и "Non-ASCII character at position...". Не забудьте удалить переменные окружения, которые на самом деле вам не нужны. При необходимости к окружению можно добавить новые переменные, однако, после запятых не должно быть пробелов, а все значения должны быть заключены в кавычки или апострофы.

После того, как файл настройки будет изменён, следует уведомить об этом Supervisor:

supervisorctl update

Если при этом Supervisor будет выдавать сообщения об ошибках, первым делом следует проверить правильность расстановки кавычек и запятых.