Python в администрировании сервера: почему бы и нет?::Журнал СА 1.2002
www.samag.ru
     
Поиск   
              
 www.samag.ru    Web  0 товаров , сумма 0 руб.
E-mail
Пароль  
 Запомнить меня
Регистрация | Забыли пароль?
Журнал "Системный администратор"
Журнал «БИТ»
Подписка
Архив номеров
Где купить
Наука и технологии
Авторам
Рекламодателям
Контакты
   

  Опросы
  Статьи

Дата-центры  

Дата-центры: есть ли опасность утечки данных?

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

 Читать далее...

Событие  

В банке рассола ждет сисадмина с полей фрактал-кукумбер

Читайте впечатления о слете ДСА 2024, рассказанные волонтером и участником слета

 Читать далее...

Организация бесперебойной работы  

Бесперебойная работа ИТ-инфраструктуры в режиме 24/7 Как обеспечить ее в нынешних условиях?

Год назад ИТ-компания «Крок» провела исследование «Ключевые тренды сервисного рынка 2023». Результаты

 Читать далее...

Книжная полка  

Читайте и познавайте мир технологий!

Издательство «БХВ» продолжает радовать выпуском интересных и полезных, к тому же прекрасно

 Читать далее...

СУБД PostgreSQL  

СУБД Postgres Pro

Сертификация по новым требованиям ФСТЭК и роль администратора без доступа к данным

 Читать далее...

Критическая инфраструктура  

КИИ для оператора связи. Готовы ли компании к повышению уровня кибербезопасности?

Похоже, что провайдеры и операторы связи начали забывать о требованиях законодательства

 Читать далее...

Архитектура ПО  

Архитектурные метрики. Качество архитектуры и способность системы к эволюционированию

Обычно соответствие программного продукта требованиям мы проверяем через скоуп вполне себе понятных

 Читать далее...

Как хорошо вы это знаете  

Что вам известно о разработках компании ARinteg?

Компания ARinteg (ООО «АРинтег») – системный интегратор на российском рынке ИБ –

 Читать далее...

Графические редакторы  

Рисование абстрактных гор в стиле Paper Cut

Векторный графический редактор Inkscape – яркий представитель той прослойки open source, с

 Читать далее...

День сисадмина  

Учите матчасть! Или как стать системным администратором

Лето – время не только отпусков, но и хорошая возможность определиться с профессией

 Читать далее...

День сисадмина  

Живой айтишник – это всегда движение. Остановка смерти подобна

Наши авторы рассказывают о своем опыте и дают советы начинающим системным администраторам.

 Читать далее...

Виртуализация  

Рынок решений для виртуализации

По данным «Обзора российского рынка инфраструктурного ПО и перспектив его развития», сделанного

 Читать далее...

Книжная полка  

Как стать креативным и востребованным

Издательский дом «Питер» предлагает новинки компьютерной литературы, а также книги по бизнесу

 Читать далее...

Книжная полка  

От создания сайтов до разработки и реализации API

В издательстве «БХВ» недавно вышли книги, которые будут интересны системным администраторам, создателям

 Читать далее...

1001 и 1 книга  
19.03.2018г.
Просмотров: 6227
Комментарии: 0
Машинное обучение с использованием библиотеки Н2О

 Читать далее...

12.03.2018г.
Просмотров: 6933
Комментарии: 0
Особенности киберпреступлений в России: инструменты нападения и защита информации

 Читать далее...

12.03.2018г.
Просмотров: 4216
Комментарии: 0
Глубокое обучение с точки зрения практика

 Читать далее...

12.03.2018г.
Просмотров: 3006
Комментарии: 0
Изучаем pandas

 Читать далее...

12.03.2018г.
Просмотров: 3807
Комментарии: 0
Программирование на языке Rust (Цветное издание)

 Читать далее...

19.12.2017г.
Просмотров: 3821
Комментарии: 0
Глубокое обучение

 Читать далее...

19.12.2017г.
Просмотров: 6316
Комментарии: 0
Анализ социальных медиа на Python

 Читать далее...

19.12.2017г.
Просмотров: 3170
Комментарии: 0
Основы блокчейна

 Читать далее...

19.12.2017г.
Просмотров: 3460
Комментарии: 0
Java 9. Полный обзор нововведений

 Читать далее...

16.02.2017г.
Просмотров: 7278
Комментарии: 0
Опоздавших не бывает, или книга о стеке

 Читать далее...

17.05.2016г.
Просмотров: 10646
Комментарии: 0
Теория вычислений для программистов

 Читать далее...

30.03.2015г.
Просмотров: 12365
Комментарии: 0
От математики к обобщенному программированию

 Читать далее...

18.02.2014г.
Просмотров: 13999
Комментарии: 0
Рецензия на книгу «Читаем Тьюринга»

 Читать далее...

13.02.2014г.
Просмотров: 9124
Комментарии: 0
Читайте, размышляйте, действуйте

 Читать далее...

12.02.2014г.
Просмотров: 7079
Комментарии: 0
Рисуем наши мысли

 Читать далее...

10.02.2014г.
Просмотров: 5388
Комментарии: 3
Страна в цифрах

 Читать далее...

18.12.2013г.
Просмотров: 4617
Комментарии: 0
Большие данные меняют нашу жизнь

 Читать далее...

18.12.2013г.
Просмотров: 3427
Комментарии: 0
Компьютерные технологии – корень зла для точки роста

 Читать далее...

04.12.2013г.
Просмотров: 3155
Комментарии: 0
Паутина в облаках

 Читать далее...

03.12.2013г.
Просмотров: 3402
Комментарии: 0
Рецензия на книгу «MongoDB в действии»

 Читать далее...

02.12.2013г.
Просмотров: 3025
Комментарии: 0
Не думай о минутах свысока

 Читать далее...

Друзья сайта  

 Python в администрировании сервера: почему бы и нет?

Архив номеров / 2002 / Выпуск №1 (1) / Python в администрировании сервера: почему бы и нет?

Рубрика: Администрирование /  Продукты и решения

РОМАН ЗУСИ

Python в администрировании сервера: почему бы и нет?

Стандартных решений не существует. Каждый системный администратор рано или поздно начинает писать свои скрипты, которые облегчают его работу, избавляя от рутины. Для автоматизации в UNIX-системах традиционно применяются командные оболочки (типа bash или ksh, разновидностей оболочек достаточно много) и язык Perl. Причем, следуя философии UNIX, эти оболочки используют для решения проблемы целый набор инструментов, выполняющих небольшие частные задачи: ls, wc, sort, grep, diff, tar, ...

Обычно простые задачи выполняются в командной оболочке запуcком соответствующих инструментов и организацией потока данных. Для более сложных задач требуются и более сложные инструменты, например, awk, sed или даже Perl. Так принято.

Однако хотелось бы обратить внимание системных администраторов на такой сценарный (скриптовый) язык как Python. Этот язык, благодаря своим хорошим качествам, о которых поговорим далее, уверенно завоевывает популярность, в том числе для задач системного администрирования. Например, именно его применяет Red Hat в инструменте под названием anaconda для обеспечения начальной установки своего дистрибутива Linux.

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

Python – интерпретируемый язык с развитыми высокоуровневыми структурами данных, имеющий все необходимое для вызова функций POSIX-совместимых систем. Впрочем, Python является многоплатформенным языком, так что его можно с успехом использовать и, к примеру, в среде Windows. Однако не буду долго говорить о происхождении и синтаксисе языка: об этом заинтересованный читатель узнает на http://python.ru или из книги Сузи Р.А. Python. – СПб.: БХВ-Петербург, 2002; а сразу перейду к делу.

Начнем с небольшого примера, в котором нам требуется установить права и принадлежность файлов, чтобы имена совпадали с именами пользователей в системе (для простоты будем считать, что имена пользователей доступны из файла /etc/passwd). Подобная задача может возникнуть, например, в каталоге с почтовыми ящиками, где каждый ящик должен принадлежать соответствующему его названию пользователю.

#!/usr/bin/python

import os, string

users = {}

for line in open("/etc/passwd").readlines():

  rec = string.split(line, ":")

  users[rec[0]] = int(rec[2]), int(rec[3])   # uid и gid

for file in os.listdir("."):

  try:

    uid, gid = users[file]

  except:

    print "Сирота: ", file

    uid, gid = 0, 0  # root

  os.chmod(file, 0600)

  os.chown(file, uid, gid)

В самом начале мы импортируем модуль для работы с функциями ОС (os) и работы со строками (string). Перед началом цикла по строкам файла /etc/passwd словарь users пуст. В цикле по строкам файла /etc/passwd мы делаем следующее. Именем rec обозначаем кортеж значений записи passwd-файла. Мы знаем, что первое поле этой записи – имя пользователя. Имя пользователя и станет ключом в словаре users. В качестве значения для данного ключа мы берем приведенные к целому типу поля 2 и 3, соответствующие идентификаторам пользователя и группы. Таким образом в первом цикле формируется отображение имени пользователя и его идентификаторов. Во втором цикле, по именам файлов в текущем каталоге, пытаемся (try) найти владельца файла, обращаясь к словарю users. Если это не удается, мы пишем на стандартный вывод соответствующую диагностику. В этом случае владельцем файла станет root. Последние две команды, думается, ясны и без комментариев.

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

Для любознательных укажем и второй путь решения, в котором используются «правильные» средства:

#!/usr/bin/python

import os, pwd, glob

default = pwd.getpwnam("root")

for file in glob.glob("*"):

  try:

    rec = pwd.getpwnam(file)

  except:

    print "Сирота: ", file

    rec = default

  os.chmod(file, 0600)

  os.chown(file, rec[2], rec[3])

Здесь удалось добиться некоторого сокращения программы за счет использования функции getpwnam модуля pwd стандартной библиотеки Python. Здесь также применена функция glob из одноименного модуля для получения списка файлов.

Для сравнения приведен неправильный пример подобной же программы, написанный в оболочке bash.

#!/bin/bash

# Не работает, если имена файлов содержат точку или пробел

for file in *

do

  chown $file.$file $file || chown root.root $file

  chmod 600 $file

done

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

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

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

В следующем примере мы рассмотрим еще одну часто возникающую задачу: проверка работоспособности POP3-сервиса и отправка сообщения электронной почты в случае неудачи. Заметьте, что приведенный пример одинаково хорошо подходит и для UNIX, и для NT.

#!/usr/bin/python

import smtplib, poplib

try:

  p = poplib.POP3("mymail")

  p.quit()

except:

  error = "connection"

  try:

    s = SMTP("othermail")

    s.sendmail("admin@mymail", "admin@othermail",

"""From: admin@mymail

To: admin@othermail

Subject: POP3 down!!!

Please, restart pop3 at mymail.

""")

    s.quit()

  except:

    print "нет связи"

С помощью конструктора объекта POP3-соединения из модуля poplib мы пытаемся установить соединение с POP3-сервером mymail. Если это не удается, мы должны отправить о происшествии письмо на admin@othermail. В этом нам поможет модуль smtplib и конструктор класса SMTP. Если и это не удается, просто выводится «нет связи». Заметьте, как легко в Python ввести многострочный текст.

Надеемся, вы как минимум заинтересовались предлагаемым инструментом.

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

Таблица 1

Команда UNIX

Функция Python

cal месяц год

calendar.monthcalendar(год, месяц)

cd каталог

os.chdir("каталог")

chmod режим путь

os.chmod("путь", режим)

chown uid.gid путь

os.chown("путь", uid, gid)

cp файл путь

shutil.copy("файл", "путь")

date

time.localtime(time.time()) и другие функции модуля time

diff

функции модуля difflib

echo $перем

print "%(перем)s" % vars()

echo текст

print "текст"

exit N

sys.exit(N)

fetchmail

модуль poplib

ftp

модуль ftplib

grep, egrep

для работы с регулярными выражениями служит модуль re

gzip

модуль gzip

ln -s путь1 путь2

os.symlink("файл1", "файл2")

ln файл1 файл2

os.link("файл1", "файл2")

ls -l файл

os.stat("файл")

ls каталог

os.listdir("каталог"), glob.glob("каталог")

man тема

help("тема") или help(объект)

mkdir путь

os.mkdir(путь)

mv путь1 путь2

os.rename("путь1", "путь2")

nslookup хост

socket.gethostbyname("хост") и другие функции этого модуля

pwd

os.getcwd()

rm -R каталог

shutil.rmtree("каталог")

rm файл

os.unlink("файл") или os.remove("файл")

sendmail

модуль smtplib

sort

список.sort()

wget и т.п.

модули httplib, urllib, urllib2, urlparse

zip

модуль zipfile

команда

os.system("команда")

команда |

f = os.popen("команда", "r")

| команда

f = os.popen("команда", "w")

< файл

f = open("файл", "r"); f.read(); f.close()

> файл

f = open("файл", "r"); f.write(...); f.close()

Настало время разобрать более сложный пример – программу для анализа логов почтового сервера Sendmail. Наверное, не нужно долго объяснять, что для обеспечения бесперебойной работы сервера и требуемого качества обслуживания просто необходимо вовремя выявлять аномалии в его работе и пресекать попытки злоупотребления сервисом. Одна из основных проблем – массовые несанкционированные рассылки, или попросту спам. И проблема эта не только в том, чтобы уберечь пользователей сервера от спама, но и вовремя заметить попытки применения пользователями программ массовой рассылки.

Я почти уверен, что на рынке имеются готовые инструменты для решения этой проблемы. Даже очень возможно, что нужные программы есть в свободном распространении. Однако простые средства во многих случаях можно написать и самому, руководствуясь своим опытом и, возможно, знанием местной специфики. Тем более, что это не требует много времени.

Разбираемый ниже пример не претендует на полноту решения проблемы спама, он решает частную задачу. Мы будем отслеживать лишь попытки массовых рассылок, в которых на один «mail from» следуют несколько «rcpt to». Конечно, программу легко адаптировать и для другой ситуации, агрегируя данные по отправителям, получателям и так далее, получая портрет ситуации на почтовом сервере. Следует заметить, что глядя на «сырые» логи Sendmail не всегда можно увидеть проблему. Во всяком случае, для этого требуется некоторое напряжение глаз.

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

Накапливаемые данные мы будем сохранять в файлах-хэшах (аналогичных тем, в которых хранятся, например, псевдонимы), благо в Python есть для этого нужные модули. (Конечно, в Python можно использовать и полновесные базы данных с языком запросов SQL, однако это непринципиально).

Задача распадается на две: сбор данных из лога в базу данных и выборка из базы данных.

#!/usr/bin/python

"""Анализ лога Sendmail"""

import os, re, sys, anydbm, time

server_name = "mail"  # имя сервера, фигурирующее в логах

def createdb(file):

  """Создание БД"""

  try: os.unlink(file)  # удаляем старую БД

  except: pass  # игнорируем исключения

  return anydbm.open(file, "c")

                           # ключ: значение

f = createdb("from.db")    # ид сессии: отправитель

t = createdb("to.db")      # ид сессии: получатели

r = createdb("relay.db")   # ид сессии: почтовый хост

d = createdb("date.db")    # время и ид сессии: ид сессии

''' Примеры четырех характерных случаев:

Aug 11 20:24:25 mail sendmail[4720]: g7BGOHY2004720: from=<tegeran@mail.ru>, size=103655, class="0", nrcpts=1, msgid=<000c01c2414e$d175ad80$3075a8c0@awx.ru>, proto=SMTP, daemon=MTA, relay=[212.28.127.12]

Aug 11 20:24:25 mail sendmail[4720]: g7BGOHY2004720: to=<font@twogo.ru>, delay=00:00:07, pri=133655, stat=Headers too large (32768 max)'''

Aug 11 04:02:31 mail sendmail[17058]: g7B02UY2017058: from=<gluck@subscribe.ru>, size=33977, class="0", nrcpts=1, msgid=<20020811030027_hk_=2087=top=n=n_@subscribe:news.listsoft.lnx>, proto=SMTP, daemon=MTA, relay=relay1.aport.ru [194.67.18.127]

Aug 11 07:18:20 mail sendmail[28329]: g7B3ICY2028329: <nouser@twogo.ru>... User unknown'''

# характерные части регулярных выражений (префикс, хост и адрес)

P = "(?P<date>.{15}) %(server_name)s sendmail\[[0-9]+\]: (?P<session>[^:]+): " % vars()

R = "relay=(?P<relay>.*(?:\[(?P<relay_ip>.+?)\])?)"

A = "\<?(?P<addr>[^(),>]+)\>?"

# регулярные выражения, соответствующие разным случаям

log1_re = re.compile(r"%(P)s(?P<direc>to)=%(A)s, (.*), stat=(?P<stat>.*)" % vars())

log2_re = re.compile(r"%(P)s(?P<direc>from)=%(A)s, size=(?P<size>[0-9]+), .*, %(R)s" % vars())

log3_re = re.compile(r"%(P)s(?P<direc>from)=%(A)s, .*, %(R)s" % vars())

log4_re = re.compile(r"%(P)s%(A)s\.\.\. (?P<stat>User unknown)" % vars())

input_file = open(sys.argv[1], "r")  # открываем файл с логом

while 1:

  line = input_file.readline()

  if not line:  # обнаружен конец файла: выход из цикла

    break

  # сравниваем строку лога с шаблонами

  m = log1_re.match(line) or log2_re.match(line) or log3_re.match(line) or log4_re.match(line)

  if m:  # если хоть один шаблон сработал:

    found = m.groupdict()  # получаем словарь групп результата

    date, session_id, addr = found["date"], found["session"], found["addr"]

    direc = found.get("direc", "to")  # по умолчанию "to"

    stat = found.get("stat", "")      # по умолчанию - пустая строка

    if direc == "to" and stat[:4] != "Sent" and stat != "User unknown":

       continue  # такие сообщения не интересуют

    if direc == "to":  # в зависимости от направления

      if t.has_key(session_id):

        t[session_id] = t[session_id] + addr + ";"

      else:

        t[session_id] = addr + ";"

    else:

      f[session_id] = addr

      r[session_id] = found.get("relay_ip", "") or found.get("relay", "")

      d[date + session_id] = session_id

input_file.close()

f.close(); t.close(); r.close(); d.close()

Построчно читаем из файла с логами и, в зависимости от сработавшего шаблона, записываем в заранее открытые базы данных. Обратите внимание, что база date.db использует в качестве ключей как дату, так и идентификатор сессии. Последний делает ключ уникальным.

Заметим, что в Python логические операции or и and работают несколько необычно. Любой объект имеет так называемое истинностное значение. Нули, пустые последовательности, объект None считаются «ложью», а остальные объекты – истиной. В результате операции A or B возвращается объект A, если он «истинен», а в противном случае – объект B. Именно поэтому имени m будет соответствовать результат первого успешного сравнения.

Python оперирует такими высокоуровневыми объектами, как список и словарь. Словарь задает отображение между ключами и значениями. В частности, found является словарем, отображающим имя найденной в строке лога группы и значения этой группы. Имена групп в регулярных выражениях задаются через (?P<имя> ...). Взять из словаря значение по ключу можно не только с помощью словарь[ключ], но и с помощью метода get(). В последнем случае можно задать значение «по умолчанию», то есть значение, которое метод get() возвратит в случае отсутствия ключа в словаре.

Стоит заметить, что работа с базами данных использует тот же синтаксис, что и работа со словарями (об этом позаботились разработчики модуля anydbm).

Итак, мы поместили информацию из лога Sendmail в более удобный для обработки вид – в базы данных (хэши). Следующая программа - пример одного из обработчиков, которые мы теперь можем применить.

Для нашей цели (выявление чрезмерных списков рассылки) данные удобно отсортировать по времени. Это легко сделать с ключами из базы date.db. По сути мы считываем все ключи этой базы в память (метод keys()) и сортируем их по возрастанию.

#!/usr/bin/python

"""Анализируем собранные данные"""

import re, sys, anydbm, string

# открываем базы

f = anydbm.open("from.db", "r")

t = anydbm.open("to.db", "r")

r = anydbm.open("relay.db", "r")

d = anydbm.open("date.db", "r")

# показывать только случаи отправления >= LIM получателям

try:

  LIM = int(sys.argv[1])

except:

  LIM = 4

dkeys = d.keys()  # получаем все ключи в один список

# сортируем (фактически, по времени). Пренебрегаем сменой месяцев

dkeys.sort()

good_guys_re = re.compile(".*(gluck@subscribe.ru|-errors@maillist.ru|@lists.cityline.ru|@host4.list.ru)\Z")

def our_filter(x):

  """Функция для фильтрации получателей"""

  return "@" in x

for date_sess_id in dkeys:

  i = d[date_sess_id]  # находим идентификатор сессии

  try:

    recps = string.split(t[i], ";")  # список получателей

    # берем только адреса с @

    recps = filter(our_filter, recps)

    sender = f[i]  # отправитель

    # показываем

    if len(recps) >= LIM and not good_guys_re.match(sender):

      relay = r[i]

      dte = date_sess_id[:15]  # первые 15 символов -- дата

      print f[i], relay, dte, "->\n     ", string.join(recps, "\n      ")

  except:  # если возникли ошибки, пропускаем

    pass 

f.close(); t.close(); r.close()

Здесь особо следует отметить функцию filter(). Эта встроенная функция применяет некоторую функцию (аргумент 1) к списку (аргумент 2). В нашем случае используется our_filter, которая возвращает «истину» в случае, когда ее аргумент содержит «@».

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

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

Программисты на Python утверждают, что на этом языке можно писать «со скоростью мысли», то есть, почти все время оставаясь в предметной области. Если вы этому не верите, попробуйте переписать приведенные программы с использованием стандартного Си или Java. С другой стороны, приведенную задачу обычно решают с помощью языка Perl. К сожалению, Perl вносит очень много синтаксического мусора, что подчас значительно затеняет логику программы.

Основными преимуществами Python являются, на мой взгляд:

  • удобный и легко читаемый синтаксис;
  • многоплатформенность;
  • поддержка основных системных и сетевых протоколов и форматов;
  • большой набор библиотек;
  • свободное распространение;
  • дружелюбная поддержка в телеконференции comp.lang.python;
  • надежный и устойчивый интерпретатор.

Все это делает Python отличным инструментом в работе системного администратора.


Комментарии отсутствуют

Добавить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

               Copyright © Системный администратор

Яндекс.Метрика
Tel.: (499) 277-12-45
E-mail: sa@samag.ru