Главное меню » Практика » Linux: Python следит за системой

Linux: Python следит за системой

В этой статье мы рассмотрим язык программирования Python в качестве инструмента для получения различной информации о системе под управлением Linux.

Какой Python?

Когда я имею в виду Python, я имею в виду CPython 2 (2.7, если быть точным). Я буду говорить об этом явно, когда тот же код не будет работать с CPython 3 (3.3) и предоставлю альтернативный код вместе с объяснением различий. Просто чтобы убедиться, что у вас установлен CPython, наберите терминала python or python3, и вы должны увидеть приглашение Python, которое отобразиться в вашем терминале.
Обратите внимание, что если файл содержит первую строку вида #!/usr/bin/env python будут, то это означает, что мы хотим, чтобы интерпретатор Python мог выполнить этот файл. Следовательно, если вы сделаете свой скрипт исполняемым с помощью chmod +х script-name.py, вы можете выполнить его, используя команду ./script-name.py.

Исследуем модуль platform

Модуль platform из стандартной библиотеке имеет ряд функций, которые позволяют нам получать различную информацию о системе. Давайте запустим интерпретатор Python и изучим некоторые из них, начиная с функции platform.uname():

Если вы знаете о команде uname в Linux, вам наверное уже стало ясно, что эта функция представляет собой своего рода интерфейс к этой команде. В Python 2, она возвращает кортеж, состоящий из типа системы (или типа ядра), имени хоста, версии, номера релиза и информации об аппаратных средствах и процессоре. Вы можете получить доступ к отдельным атрибутам с помощью индексов, например так:

В Python 3, функция возвращает именованный кортеж:

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

Модуль platform также имеет интерфейсы прямого доступа для некоторых из указанных выше атрибутов, например, так:

Функция linux_distribution() возвращает информацию о используемом вами дистрибутиые Linux. Например, в системе Fedora 18, эта команда возвращает следующую информацию:

Результат возвращается в виде кортежа, состоящего из названия дистрибутива, его версии и кодового именем. Дистрибутивы, поддерживаемые вашей конкретной версией Python, можно получить, распечатав значение атрибута _supported_dists:

Если ваш дистрибутив Linux не является одним из них (или производным от одного из них), то вы, вероятно, не увидите никакой полезной информации из приведенного выше вызова функции.
Последняя функция из модуля platform, которую мы рассмотрим, это функция architecture(). При вызове этой функции без каких-либо аргументов, она возвращает кортеж, состоящий из разрядности архитектуры системы и формата исполняемого файла Python. Например:

На 32-битной системе Linux, вы увидите:

Вы получите аналогичные результаты, если вы укажете какой-либо другой исполняемый файл в системе, например, так:

Рекомендуем вам изучить другие функции модуля platform, которые среди прочего, позволят вам найти текущую версию Python. Если вам интересно узнать, как этот модуль получает информацию, вы можете посмотреть файл Lib/platform.py в каталоге с исходным кодом Python.
Модули os и sys, также представляют интерес для извлечения определенной информации о системе, например используемый вашей системой порядок байтов (Endianness). Далее мы выйдем за пределы модулей стандартной библиотеки Python, чтобы изучить некоторые общие подходы к получению доступа к информации о системе Linux, доступной через файловые системы proc и sysfs. Следует отметить, что информация, представлемая через эти файловые системы будет варьироваться между различными аппаратными архитектурами и, следовательно, вы должны иметь это в виду при чтении этой статьи, а также при написание сценариев, которые пытаются извлечь информацию из файлов в этих файловых системах.

Получаем информацию о центральном процессоре

Файл /proc/cpuinfo содержит информацию о процессорах вашей системы. Например, вот Python-версия того, что должна сделать команда cat /proc/cpuinfo:

Выполнив эту программы с помощью Python 2 или Python 3, вы должны увидеть на экране все содержимое файла /proc/cpuinfo (в приведенной выше программе, метод rstrip() удаляет завершающий символ новой строки в конце каждой из строк).
В следующем листинге используется метод startswith() для отображения моделей ваших процессоров:

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

Теперь мы знаем несколько способов определить архитектуру нашей системы. Если быть точным, оба эти подходы фактически определяют архитектуру ядра вашей системы. Так что, если ваш компьютер на самом деле ваша машина является 64-разрядной, но работает под управлением 32-битного ядра, то эти методы будут сообщать о вашей машине, как имеющей 32-разрядную архитектуру. Для того, чтобы найти истинную архитектуру машины, вы можете посмотреть на флаг lm в списке флагов в /proc/cpuinfo. Флаг lm присутствует только на компьютерах с 64-битной архитектурой. Следующая программа иллюстрирует этот подход:

Как мы видим, можно читать /proc/cpuinfo и использовать простые методы обработки текста для получения данных, котрые мы ищем. Для того, чтобы сделать эти данные более подходящими для использования в дальнейшем в других частях программиы, лучше сделать содержимое /proc/cpuinfo доступным в качестве стандартной структуры данных, например такой как dictionary. Идея проста: если вы видите содержимое этого файла, вы увидите, что для каждого процессора существует целый ряд пар ключ — значение (в предыдущем примере, мы выводили название модели процессора, здесь название модели можно использовать как ключ). Информация о различных процессорах отделена друг от друга пустой строкой. Несложно построить структуру dictionary, которая содержит данные о каждом из процессоров в качестве ключеа. Для каждого из этих ключей, значением будет вся информация о соответствующем процессоре в файле /proc/cpuinfo. Следующий листинг показывает, как вы можете сделать это.

Этот код использует OrderedDict (упорядоченный dictionary) вместо обычного dictionary, так что ключ и значения сохраняются в том порядке, в котором они находятся в файле. Следовательно, за данными о первом процессоре следуют данные о втором процессоре и так далее. Если вызвать эту функцию, она возвращает вам dictionary. Ключами dictionary является ифнормация о каждом из процессоров. Затем вы можете использовать выбрать информацию только об интересующих вас процессорах (как показано в блоке if __name__==’__main__’). Вышеприведенная программа при запуске будет еще раз выводить название модели каждого из процессоров (это выполняется с помощью команды print(cpuinfo[processor][‘model name’]):

Информация о состоянии памяти

Аналогично /proc/cpuinfo, файл /proc/meminfo содержит информацию об оперативной памяти вашего компьютера. Следующая программа создает dictionary из содержимого этого файла и выводит его на экран:

Как и раньше, вы можете также получить доступ к какой-либо конкретной информации, которую вы ищете, используя ее в качестве ключа (как показано в блоке if __name__==__main__ ). При выполнении программы, вы должны увидеть вывод, аналогичный следующему:

Сетевая статистика

Сейчас мы посмотрим, какую минформацию можно получить о сетевых устройствах нашей системы. Мы попробуем получить список сетевых интерфейсов системы и количество байт, переданных и полученных ими с момента последней перезагрузки системы. Файл /proc/net/dev поможет нам получить эту информацию. Если изучить содержимое этого файла, то вы заметите, что первые две строки содержат заголовок — т.е. первый столбец этого файла является имя сетевого интерфейса, второй и третий столбцы отображают информацию о количестве принятых и переданных байт (такую как общее количество отправленных байт, количество пакетов, ошибок и т.п.). Нам необходимо извлечь общий объем данных, переданных и принятых различными сетевыми интерфейсами. Следующий листинг показывает, как мы можем извлечь эту информацию из файла /proc/net/dev:

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

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

Процессы

Каталог /proc содержит директории для каждого из запущенных в системе процессов. Имена этих каталогов такие же, как идентификаторы процессов для этих процессов. Следовательно, при сканировании каталога /proc, собрать список всех его подкаталогов, имена которых содержат только цифры, вы получите список идентификаторы всех запущенных в системе процессов. Функция process_list() в следующем листинге возвращает список с идентификаторов всех запущенных процессов. Длина этого списка будет равна общему количеству процессов, запущенных в системе. См. следующий листинг:

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

Каждый из каталогов процессов содержит ряд других файлов и подкаталогов, которые, в свою очередь, содержат различную информацию о командной строке запущенного процесса, совместно используемых библиотеках, используемых процессом и много другой информации.

Блочные устройства

Следующая программа выводит список всех блочных устройств путем чтения из виртуальной файловой системы sysfs. Блочные устройства в вашей системе можно найти в директории /sys/block. Таким образом, в вашей системы могут быть такие каталоги как /sys/block/sda, /sys/block/sdb и т. д. Для того, чтобы найти все такие устройства, мы выполняем сканирование каталога /sys/block с помощью простого регулярного выражения для выражения.

Запустив эту программу, вы увидите результат, похожий на следующий:

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

Пишем утилиты командной строки

Все утилиты командной строки Linux объединяет один общий момент — они позволяют пользователю указать аргументы командной строки, чтобы настроить поведение программы по умолчанию. Модуль argparse позволяет вашей программе иметь интерфейс, похожий на интерфейс системных утилит Linux. Следующий листинг показывает программу, которая ищет имена всех пользователей в системе и выводит для каждого из них имя shell’а (с использованием стандартного библиотечного модуля pwd):

Запустив вышеприведенную программу, вы увидите всех пользователи вашей системы и имена их shell’ов.
Теперь, допустим, мы хотим чтобы пользователь программы имел возможность выбрать, хочет ли он видеть аккаунты, используемые системой для запуска демонов (например, для запуска Apache). Далее демонстрируется использование модуля argparse для реализации этой функции в путем дработки программы из предыдущего листинга:

Выполненив эту программы с опцией —help, вы увидите подсказку с доступными для программы опциями (и описанием того, что эти опции делают):

Пример вызова приведенной выше программы выглядит следующим образом:

Если вы передаете неверный параметр, программа выведет сообщение об ошибке:

Давайте попытаемся понять, как мы использовали модуль argparse в вышеприведенной программе. Оператор: parser = argparse.ArgumentParser(description=’User/Password Utility’) создает новый объект ArgumentParser с дополнительным описанием того, что эта программа делает.
Затем, мы добавляем аргументы, которые наша программа должна понимать, с помощью метода add_argument() в следующем операторе: parser.add_argument(‘—no-system’, action=’store_true’, dest=’no_system’, default = False, help=’Specify to omit system users’). Первый аргумент этого метода является именем параметра, котороый пользователь программы будет указывать в качестве аргумента командной строки при вызове программы, следующий параметр action=store_true указывает на то, что это булевское значение. То есть, на поведение программы влияет его наличие или отсутствие. Параметр dest определяет переменную, значение которой будет содержать значение переданной в параметер командной строки. Если этот параметр не указан пользователем, значением по умолчанию будет False, что указывает default = False. Последний параметр (help) — это сообщение, которое отображается, когда программа выводит информацию об этом параметре командной строки. Наконец, обработка аргументов происходит с использованием метода parse_args(), см: args = parser.parse_args(). После того, как парсинг параметров закончен, значения параметров, предоставленных пользователем, могут быть получены с помощью синтаксиса args.option_dest. В данном случае option_dest — это переменная, указанная в параметре dest метода add_argument(). Инструкция getusers(args.no_system) — это вызов функции getusers() со значением входного параметра взятым из переменной no_system (она, как мы помним, хранит значение, переданное пользователем в командной строке).
Следующая программа показывает, как можно определить небулевские параметры командной строки. Эта программа представляет собой переписанный код программы, выводящей список сетевых интерфейсов, в которую добавлена возможность указать интересующий вас сетевой интерфейс.

Если выполненить программу без каких-либо аргументов, он ведет себя точно так, как раньше. Однако, вы можете указать имя сетевого интерфейса, и посмотреть, что получится. Например:

Делаем наши скрипты доступными на системном уровне

С помощью этой статьи, вы можете написать один или несколько полезных для себя скриптов. Конечно, было бы неплохо, если бы вы могли использовать их в любой момент, как любой другоую команду Linux. Самый простой способ добиться этого — сделать скрипт исполняемым и настроить в Bash-alias для нашего скрипта. Можно также удалить расширение файла ‘.py’ и поместить файл скрипта в стандартный каталог для исполняемых файлов пользователя, например, /usr/local/sbin.

Другие полезные модули стандартной библиотеки

Помимо модулей стандартной библиотеки, которые мы уже рассмотрели в этой статье, существует ряд других модулей, которые могут оказаться вам полезны: subprocess, ConfigParser, readline and curses.

Источник: echorand.me


Теги: