27 марта, 2012

Часовые пояса в Java

В виду отмены перехода на зимнее время и обратно весьма актуальна проблема обновления временных зон. В Debian/Ubuntu проблема решается легко - обновлением пакета tzdata. К сожалению, часть приложений стоят особняком и данные для них приходится обновлять отдельно. В список «проблемных» программ попадают mysql со специальной утилитой и героиня поста - Java.

Для OpenJDK зоны вынесены в отдельный пакет tzdata-java и легко обновляются. Для Oracle (Sun) Java, которую требуют некоторые упёртые товарищи, придётся скачивать специальную утилиту - TZUpdater. Скачиваем, распаковываем, запускаем java -jar tzupdater.jar --update. После каждого изменения в часовых поясов утилита обновляется и её нужно снова скачивать.

Проверить корректность временных зон можно при помощи простой программы:

$ cat TestMSKtz.java 
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;

public class TestMSKtz {
  public static void main(String[] args) {

    Calendar cal = new GregorianCalendar();
    System.out.printf("Local time: %04d-%02d-%02d %02d:%02d:%02d\n", cal.get(Calendar.YEAR),cal.get(Calendar.MONTH),cal.get(Calendar.DAY_OF_MONTH),cal.get(Calendar.HOUR_OF_DAY),cal.get(Calendar.MINUTE),cal.get(Calendar.SECOND));

    cal = new GregorianCalendar(TimeZone.getTimeZone("Europe/Moscow"));
    System.out.printf("Moscow time: %04d-%02d-%02d %02d:%02d:%02d\n", cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND));

    cal = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
    System.out.printf("UTC time: %04d-%02d-%02d %02d:%02d:%02d\n", cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND));    
  }
}
$ javac TestMSKtz.java && java TestMSKtz
Local time: 2012-02-27 16:40:50
Moscow time: 2012-02-27 16:40:50
UTC time: 2012-02-27 12:40:50

После обновления зон нужно будет перезапустить java-приложения.

26 марта, 2012

yum: command not found

Не знаю, зачем продавать VPS с урезанной CentOS, наверное чтобы проще было впарить какую-нибудь панель. Маркетологи хуже политиков :(

Так или иначе сервер уже куплен, я обещал его настроит, а yum на сервере отсутствует. Немного погуглив составил рецепт для пятой версии:

rpm -Uvh http://mirror.centos.org/centos/5/os/x86_64/CentOS/python-elementtree-1.2.6-5.x86_64.rpm \
http://mirror.centos.org/centos/5/os/x86_64/CentOS/python-iniparse-0.2.3-4.el5.noarch.rpm \
http://mirror.centos.org/centos/5/os/x86_64/CentOS/python-sqlite-1.1.7-1.2.1.x86_64.rpm \
http://mirror.centos.org/centos/5/os/x86_64/CentOS/python-urlgrabber-3.1.0-6.el5.noarch.rpm \
http://mirror.centos.org/centos/5/os/x86_64/CentOS/yum-fastestmirror-1.1.16-21.el5.centos.noarch.rpm \
http://mirror.centos.org/centos/5/os/x86_64/CentOS/yum-metadata-parser-1.1.2-3.el5.centos.x86_64.rpm \
http://mirror.centos.org/centos/5/os/x86_64/CentOS/m2crypto-0.16-8.el5.x86_64.rpm \
http://mirror.centos.org/centos/5/os/x86_64/CentOS/yum-3.2.22-39.el5.centos.noarch.rpm

18 марта, 2012

GLPI: неправильная кодировка при обработке почты.

После начала использования GLPI в качестве Helpdesk всплыл весьма неприятный баг: часть обращений (тикетов) импортировались в неправильной кодировке. С первого взгляда «плохие» письма ничем не выделялись.

Тут нужно отметить, что мы используем Gmail-аккаунт. Только после отладки, стало понятно, что в «плохом» случае Gmail отдаёт тему письма в KOI8-R, а тело в UTF-8. В этой ситуации в коде GLPI происходит вызов iconv с параметрами ('KOI8-R' -> 'UTF-8').

Что же, воспроизведённый баг - половина патча. Приведённый ниже патч проработал у меня полтора месяца, проблем не выявлено.

--- inc/mailcollector.class.php.orig      2012-01-30 00:08:25.000000000 +0400
+++ inc/mailcollector.class.php   2012-01-30 01:29:35.000000000 +0400
@@ -955,6 +955,11 @@
                      $text = mb_convert_encoding($text, 'utf-8',$param->value);
                      $this->body_converted=true;
                   }
+                  if ((strtoupper($param->attribute)=='CHARSET')
+                      && function_exists('mb_convert_encoding')
+                      && strtoupper($param->value) == 'UTF-8') {
+                     $this->body_converted=true;
+                  }
                }
             }
             return $text;

P.S. Разработчикам отписал

15 марта, 2012

Генерация самоподписанного сертификата с openSSL

Переработка этой статьи, чтобы не искать её каждый раз, когда нужно сгенерировать сертификат.

Для начала сгенерируем ключ. OpenSSL не позволяет сгенерировать ключь, не защищенный паролем. Nginx не запускается с ключем, защищенным паролем. Чтобы устранить противоречия, сначала создаётся защищенный ключ, потом с него снимается защита.

# openssl genrsa -des3 -out server.key.encrypted 2048
 Generating RSA private key, 2048 bit long modulus
 ........+++
 ..................+++
 e is 65537 (0x10001)
 Enter pass phrase for server.key.encrypted:
 Verifying - Enter pass phrase for server.key.encrypted:
# openssl rsa -in server.key.encrypted -out server.key
 Enter pass phrase for server.key.encrypted:
 writing RSA key
# rm server.key.encrypted

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

# openssl req -new -key server.key -out server.csr
 You are about to be asked to enter information that will be incorporated
 into your certificate request.
 What you are about to enter is what is called a Distinguished Name or a DN.
 There are quite a few fields but you can leave some blank
 For some fields there will be a default value,
 If you enter '.', the field will be left blank.
 -----
 Country Name (2 letter code) [AU]:RU
 State or Province Name (full name) [Some-State]:Moscow
 Locality Name (eg, city) []:Moscow
 Organization Name (eg, company) [Internet Widgits Pty Ltd]:Mind
 Organizational Unit Name (eg, section) []:
 Common Name (eg, YOUR name) []:example.ru
 Email Address []:

 Please enter the following 'extra' attributes
 to be sent with your certificate request
 A challenge password []:
 An optional company name []:
# openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
 Signature ok
 subject=/C=RU/ST=Moscow/L=Moscow/O=Mind/CN=example.ru
 Getting Private key