27 мар. 2014 г.

Ошибка после установки Zabbix: Zabbix server is not running: the information displayed may not be current

Если вы установили серверную часть системы мониторинга Zabbix на системах RHEL (Oracle Linux, RedHat, CentOS) и вроде бы всё правильно, но в веб-интерфейсе вылазит ошибка
Zabbix server is not running: the information displayed may not be current

то, здесь обычно 2 варианта:

  • самый простой - не запущен или не корректно сконфигурирован демон zabbix-server. Проверьте, совпадают ли номера портов в конфигах zabbix-server (/etc/zabbix/zabbix_server.conf) и zabbix-web (/etc/zabbix/web/zabbix.conf.php), а так же правильно ли настроено подключение к БД.
  • если всё в конфигурационных файлах правильно и демон запущен, это скорее всего значит, что вам надо или отключить систему защиты SeLinux совсем или - что будет корректнее - изменить политику доступа к портам системы для демона httpd.

1. Проверим, что проблема действительно в настройках SeLinux:

tail -f /var/log/audit/audit.log |grep -i avc

Должны периодически добавляться в лог строки вроде этой:

type=AVC msg=audit(1395664684.460:297): avc:  denied  { name_connect } for  pid=3078 comm="httpd" dest=10051 scontext=unconfined_u:system_r:httpd_t:s0 tcontext=system_u:object_r:zabbix_port_t:s0 tclass=tcp_socket

а команда:

getsebool -a | grep zabbix

должна в таком случае дать результат:

zabbix_can_network --> off

Изменим политику для httpd:

setsebool -P httpd_can_network_connect on

Проверяем:

getsebool httpd_can_network_connect

Результат должен быть следующий:

httpd_can_network_connect --> on

Теперь веб-интерфейс Zabbix должен нормально подключаться к серверу через порт 10051 (по-умолчанию) и ошибка исчезнет.

24 мар. 2014 г.

Установка и удаление X-сервера для RHEL Linux

Устанавливать X-сервер на серверную машину конечно же не правильно. Но бывают ситуации, когда без этого не обойтись. Например, нужно установить что-либо, а установщик только GUI и экспортировать дисплей нельзя. Для этого можно установить X-сервер (в этой статье будет использован оконный менеджер Gnome), сделать дело и удалить X-сервер полностью.

В общем, от философии к делу.

Для установки X-сервера в RHEL-подобных ОС Linux (Oracle Linux, RedHat, CentOS, Fedora), которые были установлены без Xorg достаточно выполнить команду:

yum groupinstall "GNOME Desktop Environment" "X Window System" "Desktop"

В большинстве случаев создавать/редактировать конфигурационные файлы не понадобиться. Колдовать с конфигом Xorg придётся в случае нестандартных драйверов, режима нескольких мониторов и т. п., что не есть наш случай просто временной установки X-сервера. Запускаем X-сервер:

startx

Далее логинимся, делаем своё черное дело и после этого можно так же легко удалить X сервер вместе со всеми его пакетами:

yum groupremove "GNOME Desktop Environment" "X Window System" "Desktop"

21 мар. 2014 г.

Использование библиотеки Mechanize в Python для авторизации, отправки веб-форм и скачивания файлов

Для языка Python существует довольно много библиотек для работы с веб-ресурсами. Это и стандартная urllib / urllib2 и сторонние - mechanize, Twill, Request, Client Form.

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

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

Проблема заключалась в следующих моментах:

  • для скачивания нужно было авторизоваться на сайте. Причем, авторизация с помощью forms, а не Basic HTTP. 
  • необходимо было хранить кукисы, дабы авторизация не пропала. 
  • путем манипуляций со списками (SelectControl) выбирались параметры скачивания. 
  • далее нужно было получить ссылку, содержащую уникальный токен, не позволявший сачать файл по одной и той же ссылке боле 1 раза просто поменяв параметры GET запроса. 
  • и авторизация и скачивание и всё остальное нехорошие программисты сделали на одной html-странице в одной и той же форме, только с разными кнопками типа Submit.

Итак, начнемс. Вначале импорт необходимых библиотек. Mechanize не идет в стандартной поставке с Python  и его необходимо установить или с помозью PiPy или вручную, как написано на официальном сайте (python setup.py install).


import cookielib, shutil, os
from mechanize import Browser

Далее, создаем объекты: основной Browser и объект для хранения кукисов, который прикрепляем к нашему Browser. Объект Browser представляет собой контейнер по смыслу похожий на вкладку настоящего браузера. Т. е. в пределах его можно оществлять навигацию по web-сайту, авторизацию, хранить кукисы и т. д.


br = Browser()
# Create cookie jar and attach it to Browser
cj = cookielib.LWPCookieJar()
br.set_cookiejar(cj)

Затем, добавляем html хэдэры и открываем URL нужной странички в объекте Browser.


# Add some headers
br.addheaders = [('User-agent', 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.1) Gecko/2008071615 Fedora/3.0.1-1.fc9 Firefox/3.0.1')]
# Open url in Browser instance
br.open('http://www.example.com/download.aspx')

Далее выбираем форму, в которую будем вносить данные. nr=0 - индекс формы по счету в коде веб-страницы (0,1,2 ...) И вводим данные в поля для авторизации в формате (для элементов типа TextControl):

br["id_html_элемента"] = "Значение"

id элементов и возможные значения можно посмотреть двумя способами:
  • в браузере Google Chrome нажать правой кнопкой мыши на нужном элементе и выбрать Просмотр исходного кода элемента, затем правой кнопкой на выделенном элементе и Copy as HTML. После этого, вставить текст в любой текстовый редактор. 
  • выполнив код в интерпретаторе python или в отдельном скрипте:

import cookielib
from mechanize import ParseResponse, urlopen
response = urlopen("http://www.eoddata.com/download.aspx")
forms = ParseResponse(response, backwards_compat=False)
form = forms[0]
print form

Вы получите список всех элементов формы и их возможных значений в формате:

<Тип(id=список_значений)>

Вроде такого:

<aspnetForm POST http://www.example.com/download.aspx application/x-www-form-urlencoded
  <SelectControl(ctl00$DataFormat=[17, 2, 36, 16, 27, 28, 33, 32, 8, 24, 35, *9, 1, 39, 11, 14, 6, 5, 4, 12, 3, 26, 15])>
  <SubmitControl(ctl00$Download=Download) (readonly)>
  <TextControl(ctl00$txtEmail=)>
  <PasswordControl(ctl00$txtPassword=)>
  <CheckboxControl(ctl00$Remember=[on])>
  <SubmitControl(ctl00$btnLogin=Login) (readonly)>>

Итак, пример кода основного скрипта для авторизации:


# Select form for modification and "enter" login info
br.select_form(nr=0)
br["ctl00$txtEmail"] = "User"
br["ctl00$txtPassword"] = "Secret"
# Submit form
br.submit(nr=3)

Обратите внимание на строку

br.submit(nr=3)

В скобках указан номер кноки типа Submit по порядку её нахождения в html-коде страницы. Это важно, если в форме есть несколько кнопок типа Submit, но выполняющих различные функции (как в нашем случае). Нумерация 0,1,2...

Далее, выбираем необходимые данные в списках значений, например (значения посмотреть описанными выше методами):


br.select_form(nr=0)
# Select Options
br["ctl00$cboSomething"] = ["EXAMPLE",]
br["ctl00$cboDataFormat"] = ["11",]
# Update page
br.submit(nr=1)

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

Скачиваем файл (считая, что искомый URL на файл находится в переменной download_url):


local_path = "/home/user"
filename = "very_important.txt"
f = br.retrieve(download_url)[0]
# Copy saved file to normal location
shutil.copy2(f,os.path.join(local_path, filename))

В переменной f мы получаем путь к скачанному файлу, обычно это какое-то случайное имя в директории /tmp. Далее перемещаем его в нужное нам место.

Ссылки:
  • http://stockrt.github.io/p/emulating-a-browser-in-python-with-mechanize/
  • http://www.voidspace.org.uk/python/articles/authentication.shtml
  • http://mozgovipc.blogspot.com/2012/06/python-http-basic-authentication-with.html
  • http://docs.python-requests.org/en/latest/
  • http://stackoverflow.com/questions/9541677/urllib2-post-request
  • http://docs.python.org/2/howto/urllib2.html
  • http://stackoverflow.com/questions/9288662/need-more-mechanize-documentation-python
  • http://www.pythonforbeginners.com/cheatsheet/python-mechanize-cheat-sheet
  • http://blog.spritecloud.com/2010/01/posting-forms-with-python/

Регулирование частоты CPU (энергосбережение) в Linux Debian

CPU загружен полностью не всегда, потому для повышения энергосбережения современные поколения процессоров позволяют уменьшать свою частоту во время простоя. В Windows Vista, 7, 8 этот принцип реализован по-умолчанию (включается/выключается в настройках BIOS), а в OS Linux для этого нужно установить специального демона cpufrequtils:

aptitude install cpufrequtils

Он запустится и по-умолчанию в нем настроен т. н. governor (регулятор) управления частотой ondemand. Регуляторы бывают:
  • performance, производительность (по умолчанию). Этот регулятор встроен в ядро и заставляет работать CPU с максимальной скоростью; 
  • ondemand. Динамически изменяет частоту процессора в зависимости от нагрузки на систему (повышает частоту при достижении 95% нагрузки на текущей частоте); 
  • conservative. Похоже на регулятор ondemand, разница лишь в том, что повышает частоту при достижении 75% нагрузки на текущей частоте; 
  • powersave. Выставляет минимальную частоту для процессора; 
  • userspace. Пользователь выставляет частоту вручную. 
Задать регулятор можно в файле /etc/default/cpufrequtils (если его нет, нужно создать), например:

# valid values: userspace conservative powersave ondemand performance 
# get them from cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors
GOVERNOR="conservative"

14 мар. 2014 г.

Определение и вызов fabric task в одном Python скрипте

Библиотека fabric для Python является хорошим средством для автоматизации действий (админимстрирования, deployment и т. д.) для инфраструктуры серверов под управлением ОС Linux. Библиотека использует протокол open ssh для выполнения команд и перемещения данных.

Подробнее о библиотеке можно прочитать на официальном сайте или здесь.

Бывают ситуации, когда необходимо в одном скрипте и объявить таск из библиотеки fabric и выполнить его.

Пример структуры такого скрипта:

#!/usr/bin/env python
# Script dependencies: python-devel, fabric (https://github.com/fabric/fabric/archive/master.zip)
# Usage: python script.py
import fabric
from fabric.api import *
# Define ssh-like address user@server_hostname
remote_host = user@server

def some_fab_task():
    # Define fabric task here
    # hide('everything') helps to execute task with minimum output to console
    with settings(hide('everything')):
        try:
           ....
        except:
           ....

# Main function
if __name__ == '__main__':
    # Call fabric task from here
    fabric.tasks.execute(some_fab_task, hosts=[remote_host])

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

Update:

Для передачи аргументов в скрипт, указываем их перед hosts=.


fabric.tasks.execute(some_fab_task, arg1, arg2, hosts=[remote_host])

Для передачи xargs, можно указывать их также до или после hosts=


fabric.tasks.execute(some_fab_task, arg1, arg2, hosts=[remote_host], xarg1=value1)

6 мар. 2014 г.

Автоматизация скриптов с помощью expect

Недавно открыл для себя интересную консольную утилиту expect. Сия утилита является интерпретатором (со своим языком) для взаимодействия с интерактивными (т. е. требующими какого-либо ввода от пользователя) программами.

Дабы не писать много лишнего, рассмотрим использование expect на примере.

Допустим,
  • есть удалённый sftp-сервер с адресом 192.168.1.2, 
  • к которому у нас есть доступы вида user/SECRET, порт 20022,
  • нам нужно автоматически брать с этого сервера файл вида TODAYDATE_smtng_important.txt, где TODAYDATE - текущая дата вида YYYYMMDD, 
  • файлик лежит в корневой директории.
При авторизации на sftp-сервере требуется ввод пароля, который никак ни опцией ни указать, ни ключ не прокинуть (предположим, нет административного доступа на sftp-сервер).

Вот именно здесь в автоматизации этой задачи поможет нам линуксовая консольная утилита expect.

создаем файл get_file.sh со следующим содержимым:

#!/usr/bin/expect
# Script to get important file from sftp quetly. Uses expect (yum install expect -y)
# Usage: ./get_file.sh YYYYMMDD
# where YYYYMMDD - today's date

set today [lindex $argv 0]
spawn sftp -oPort=20022 user@192.168.1.2:${today}_smtng_important.txt /home/user/${today}_smtng_important.txt
expect "password:"
send "SECRET\n";
interact

Строки после комментария:
  1. Создаем переменную today, присваивая ей первый аргумент, переданный скрипту при запуске.
  2. Выполняем команду для подключения к sftp, где вместо ${today} интерпретатор вставляет значение даты (переданное скрипту)
  3. Далее скрипт ждет указанного запроса (prompt) - здесь возможно много вариантов, в т. ч. и таймауты и различные prompt-ы, об этом можно прочитать в мане или в более расширенных статьях.
  4. Получив указанный выше промпт, посылаем в ответ наш пароль и знак окончания строки (аналог нажатия пользователем [Enter])
  5. Далее скрипт полностью передает управление пользователю.
Запускать скрипт, понятное дело после chmod o+x, например так:

./get_file.sh 20142902

Минусом изложенного подхода, конечно же, является хранение пароля для sftp в открытом, не зашифрованном виде.

Ссылки:

  1. Хорошая статья по командам expect
  2. Туториал по expect
  3. Ман по sftp в Linux