LINUX.ORG.RU

Сообщения DRVTiny

 

Glusterfs с арбитром в split-brain: почему не переходит в read-only?

Форум — General

Вопрос такой: есть том glueser в конйфигурации replica 2 arbiter 1, состоящий из следующих glusterfs-bricks:

COD01:
   master:/mnt/glue
   arbiter:/mnt/glue
COD02:
   slave:/mnt/glue

На master и slave том смонтирован (в /data/gluster/glueser, но это не важно в контексте повествования и вопроса).

Если изолировать любую из нод (master или slave), то не только операции записи, но почему-то и операции чтения фейлятся на изолированном узле. Ну ок, там client-quorum does not met, но почему нельзя хотя бы read-only оставить? Может, есть какой-то патч/фикс, чтобы, например, если slave оказался в одиночестве по причине того, что COD1 упал, то хотя бы читать-то с него можно было нормально, используя том гластера, а не прямой доступ к файлам на /mnt/glue

 , ,

DRVTiny ()

logrotate и copytruncate: почему размер файла не обнуляется?

Форум — Admin

Делаю такой тест:

Запускаю скрипт, который открывает файл в режиме чтения и дописывает в него по строке раз в 0.1 секунду.

Запускаю logrotate с опцией copytruncate в конфиге, который должен обрезать файл по достижении им maxsize 10K (и сжимать потом ротированное)

Что имею в итоге: сжатая копия файла лога создаётся, всё ОК.

Исходный файл при этом не обнуляется. При этом в режиме logrotate -v пишет, что он собирается обнулить файл, чего в действительности не происходит.

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

В общем, как же так и почему copytruncate столь странно себя ведёт? logrotate стоит версии 3.16 (проверял и на дистрибутивном 3.8).

P.S. Ведержка из man logrotate.conf, чтобы вам самим не искать:

copytruncate
Truncate the original log file to zero size in place after creating a copy, instead of moving the old log file and optionally creating a new one.
It can  be used when some program cannot be told to close its logfile and thus might continue writing (appending) to the previous log file forever. 
Note that there is a very small time slice between copying the file and truncating it, so some logging data might be lost.

 ,

DRVTiny ()

Вышел Crystal 0.34.0

Новости — Разработка
Группа Разработка

Вышла новая версия Crystal, компилируемого языка программирования с синтаксисом Ruby, главные особенности которого — рантайм с «вмонтированным» event loop’ом, в котором все операции ввода-вывода асинхронны, поддержка многопоточности (пока включается флагом при компиляции) и исключительно простая и удобная работа с библиотеками на Си.

Начиная с версии 0.34.0, язык официально начинает твёрдой поступью двигаться в сторону первого настоящего релиза (т.е. версии 1.0).

В новой версии Crystal можно отметить следующие изменения и улучшения в порядке их важности:

  • В API добавлена новая библиотека журналирования Log, которая, в отличие от старой, умеет направлять сообщения в разные бекенды и по-разному эти сообщения фильтровать в зависимости от «источника».

  • Рудименты из мира разработки на Си, Errno и WinError, использовавшиеся для примитивов ввода-вывода, уходят в прошлое благодаря иерархии исключений IO::Error (впрочем, использовать Errno никто пока не запрещает).

  • Убрана автоматическая подстановка else nil из оператора case/when/else. Это сделано для того, чтобы исключить случайный пропуск разработчиком одной из веток when при матчинге по детерминированным случаям наподобие enum’ов и прохода по типам из Union’а. Т.е., проще говоря, вот такой код больше работать не будет без указания ещё одного when (when Char) или задания else-ветки:

a = 1 || 'x' || "foo"
case a
when Int32
  # ...
when String
  # ...
end
  • Опция компилятора disable_overflow больше недоступна. Для операций с переполнением используйте методы &+, &-, &*.

  • Array#fill теперь летает быстрее пули, благодаря замене туповатого цикла на один простой memset;

  • Менеджер шардов (пакетов), называющихся, как это ни парадоксально, shards, теперь использует более быстрый и эффективный алгоритм удовлетворения зависимостей Molinillo, подсмотренный в CocoaPods (Swift) и Builder (Ruby).

  • Добавлена поддержка LLVM 10, что по идее даст нам некий рост производительности, стабильности, etc.

… и множество других, на мой субъективный взгляд, менее существенных улучшений.

Хотелось бы отметить, что Crystal — это построенный на LLVM язык, позволяющий писать приложения порой быстрее, проще и лаконичнее, чем на его интерпретируемых «собратьях», и при этом получать на выходе довольно шустрый бинарник. На фоне Golang выделяется абсолютно полноценным ООП, поддержкой дженериков и очень простым и понятным синтаксисом. По своему назначению во многом аналогичен Nim, но при этом явным образом ориентирован на практическое применение «здесь и сейчас», благодаря чему имеет в своём API-арсенале множество нормально документированных удобных и качественных инструментов, поддерживаемых разработчиками языка и потому весьма стабильных.

>>> Анонс в блоге Crystal

 , ,

DRVTiny ()

Запускалка BMPN для скриптовой автоматизации?

Форум — Admin

В чём загвоздка: есть груда скриптов, связанных друг с другом событиями. Некоторые скрипты вызывают другие просто так, некоторые ждут, пока что-нибудь не появится (почтовое сообщение, например), некоторые запускаются через интервал времени X после завершения предыдущего. Есть логические ветвления, всё как в обычной BPMN-диаграмме.

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

Хотелось бы всё это задвинуть на BMPN executor, разбив весь процесс на связанные событиями куски. Например, скрипт шлёт почту удалённой системе - следующий шаг будет сделан только тогда, когда удалённая система ответит почтовым сообщением (вот как-то так оно всё сделано, к сожалению). В этом случае можно и замониторить через REST API, на каком этапе процесс находится, можно легко настроить процесс, а главное - это самодокументированная вещь, поскольку документацию никто писать не любит.

Посмотрел Camunda, у него тотальная привязка скриптов к Groovy/Java, что мне не очень нравится. Посмотрел Bonita - там можно /bin/sh запускать, вроде подходит. Сервер BPM Executor’а должен быть там же, где всё это запускаемое по крону хозяйство.

Ну мало ли вдруг кто уже сталкивался с подобным… Печально конечно, что все BPM-системы написаны на Java - а значит, живут в своём собственном мире и не знают ни про какие STDIN, STDOUT, параметры командной строки и всё прочее. Между тем, нужен в идеале инструмент «поближе к системе», менее абстрактный что ли.

Заранее Гигантское СПАСИБО!

 , , ,

DRVTiny ()

Запуск Google Chrome в изолированном окружении

Форум — Desktop

Здравствуйте,

Прошу совета: хотелось бы мне запускать Google Chrome так, чтобы он не мог сжирать всю оперативную память, залезая в своп. Проц вроде не сильно жрёт, но в принципе хотелось бы количеством процессорного времени тоже управлять (хотя тут и renice поможет).

Нужен максимально user friendly способ, который легко повторить на любой системе, в которой я работаю. Извраты с docker/lxc тоже принимаются, но нужна не концепция, а всё-таки какое-то готовое решение тогда (концептуально итак понятно, что так оно будет работать).

Я пробовал ограничивать Chrome control group'ами, что-то нифига не вышло: ставлю лимит в 40Мб, положим, Хром реально жрёт все 500, и ему хоть бы хны. Опять же, скорее всего это просто кривые руки, и мне нужно просто почитать немного документации, но всё же... задача кажется тривиальной для Linux, поэтому меня не покидает ощущение, что я упускаю из виду какой-то простой способ, не предполагающий написания длинных витиеватых скриптов или установки всей инфраструктуры docker.

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

В идеале - сожрал Chrome больше лимита памяти - убиваем его к такой ядрёной фене, и дело с концом.

Нашёл такой вариант: https://askubuntu.com/questions/836469/install-cgconfig-in-ubuntu-16-04, но мой Linux Mint про все перечисленные конфиги ничего не знает, а cgconfigparser'а там просто нет (хотя все перечисленные в том совете пакеты поставил).

 , ,

DRVTiny ()

Поиска софта тред: централизация алертинга/нотификаций?

Форум — Admin

Нашёл пока только flapjack, написанный на JS'е. Примитивен, недоразвит, страшон, как смерть.

Хотелось бы от разных приложений (в основном систем мониторинга разного класса и уровня) отправлять абстрактные алерты пользователям в некий движок, который дальше уже сам решит, что такому-то нужно sms отправить, другому - email (и адрес желательно взять из LDAP-каталога), для группы товарищей - отправить уведомление ботом в телеграм-группу (ок, последнее конечно через внешний скрипт).

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

Может, кто подскажет ещё интересные варианты?

Спасибо!

 ,

DRVTiny ()

Как вежливо убить linux-тред по таймауту?

Форум — Development

Такой языко-агностичный вопрос:

Нужно запустить некий кусок вычислений в параллель (создать поток для него) и убить этот кусок вычислений через N_EXEC_TIMEOUT секунд. Но убить «грациозно», отправив некий сигнал потоку, выполняющему вычисления.

Вопрос в том, что поток не может обрабатывать сигнал (ALRM, например) монопольно, ведь таких кусков вычислений в один и тот же момент времени может быть сколько угодно.

Правильно ли я понимаю, что pthread_kill каким-то чудесным образом решает эту проблему (корень которой в том, что обработчики сигналов ставятся на уровне процесса, а на уровне потока можно только замаскировать получение сигналов)?

Есть ли в реалтаймовых расширениях для ядра Linux некий механизм, позволяющий ограничивать время работы потока? Что-то вроде «суммарное время исполнения кода этого потока не может превышать 500 ms, если больше - сначала запусти предопределённый soft-обработчик, определённый в коде потока, а если нет такого или после запуска soft-обработчика поток добрался до верхней hard-границы времени исполнения, то просто освободить все ресурсы потока и убить его»?

В итоге это всё нужно для того, чтобы можно было делать что-то вроде:

# async, "green" thread
spawn do
  # 2 pthreads will be created:
  # 1-st is a watchdog thread to break our calculations on timeout
  # 2-nd - for calculations itself
  # 1-st is watching for 2-nd thread status. It will terminate if 2-nd thread exited OR timeout occured
  # our async/"green" thread will yield/block while joining the 2-nd thread
  result = with_timeout do
    ... some code ...
  end
rescue Exception::Timeout
  puts "Timeout occured"
end

 , ,

DRVTiny ()

Как принимать HTTP на фронтенде и коннектиться по HTTPS к бэкенду?

Форум — Admin

Есть API приложения, которое, к огромному сожалению, доступно только по HTTPS. Поскольку приложение находится внутри корпоративной сети и никакие враги там мега-секретные ответы API не перехватывают - хотелось бы избавить клиентскую сторону от геморроя с сертификатами и дать нормальный человеческий HTTP-доступ, при этом также предоставив load-balancing и failover, поскольку на стороне бэкенда не 1 сервер, а целая кластерная россыпь равнозначных серверов, каждый из которых имеет моральное право рухнуть в любой момент.

Конфигурацию проксирования HTTPS в HTTP для haproxу описали бешенное количество раз, а вот с обратным как всегда какая-то дикая проблема, прямо-таки секрет полишинеля какой-то (словно речь идёт о каких-то страшных непристойностях). Я уже делал аналогичную схему для LDAP -> LDAPS, и пока получилось - чуть мозг не вывихнул, теперь вот аналогичный геморрой с HTTP...

Может, у кого уже есть наработки / примеры? Был бы очень благодарен!

 

DRVTiny ()

Посоветуйте Event Broadcasting System, но не Kafka?

Форум — Development

Задача такая:

Есть именованные шины сообщений/событий - на которые разными источниками выкладываются сообщения в режиме «отправил - и забыл». Никакой связи между источниками и получателями нет.

Нужна некая система, которая обеспечивает:

а) У неё есть отказоустойчивые клиенты как для роли получателя, так и для роли отправителя (на стороне отправителя сообщения откладываются в буфер и делаются попытки реконнекта в случае наличия проблем соединения, на стороне получателя - просто постоянные попытки реконнекта после обрыва связи)

б) Система предоставляет получателю возможность запросить «все доступные/сохранённые сообщения из шины с именем N,начиная с id=X». При этом система имеет право отдать только те сообщения из шины, которые она в разумных пределах «окна исторических данных» временно сохранила

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

в - необязательное требование.

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

Есть ли что-нибудь менее универсальное, чем Kafka и, желательно, ориентированное именно на «событийное широковещание»?

Спасибо!

 , , ,

DRVTiny ()

Как подписаться на событие «появился слушающий tcp-сокет»?

Форум — Development

Предполагаю, что теоретически можно через inotify подписаться на изменения файла /proc/net/tcp - и отсеивать ненужные/неинтересные изменения, ожидая «свой» сокет :)

Но вообще непонятно на самом деле: вот у тебя закрылся сокет по причине дисконнекта. И хотелось бы просто поставить обработчик «когда поднимется обратно - выполнить something (пересоздать объекты, работающие с данным сокетом и вообще пересоздать мир заново)». Но остаётся только долбить ОС постоянно попытками подключения на несуществующий сокет. Хорошо ли это? Я вот столкнулся с ситуацией, когда оказалось не очень хорошо: сокет используется для «широковещания» через Redis, и накопленные за время время падения сервиса сообщения отправляются так, что не все подписчики успевают их поймать. Может, оно и не мега-критично, но если бы и подписчики, и отправители восстанавливали соединение ASAP - такой фигни бы не было. А просто так долбить закрытый сокет каждые 10 мс, например - тоже не дело...

Вот если б подписаться - в том бы толк однозначно был.

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

 , ,

DRVTiny ()

Чем бы нарисовать сервисную топологию IT-инфраструктуры?

Форум — Admin

Вопрос простой (но на самом деле нет :))

Как, в чём можно было бы в WebGUI интерфейсе, мышкою нарисовать топологию IT-инфраструктуры со всеми её вложенностями и хитроумными взаимосвязями - и при этом получить на выходе веб-сервис или хотя бы базу данных, из которой можно было запрашивать данные об объектах?

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

Такие чудеса есть или только UML, только хардкор?

P.S. В Enterprise-продуктах HP такого полно, но у нас нет оных продуктов и в силу потенциальной токсичности HP для российского бизнеса - и не предвидится.

 , ,

DRVTiny ()

shadowsocks - оптимален для подключения к телеграм?

Форум — Admin

Хочу невозможного: настроить sock5-прокси в мобильном клиенте телеги, но при этом не выставлять на VPS свой прокси голой Ж наружу.

Похоже, shadowsocks это умеет: он устанавливается как локальный sock5-прокси на android и позволяет проксировать трафик в шифрованном виде до shadowsocks'а на VPS'ке.

Или я неправ?

 ,

DRVTiny ()

Как можно было бы пользоваться телегой, если бы Дуров сие поддержал :)

Форум — Talks

1) Создаём VPS в зарубежах

2) iptables'ом Перанаправляем порт X на порт Y socks5-сервера телеграма

От Дурова - только sock5-сервер.

Преимущества подхода:

+ Не нужно настраивать VPN, который чреват геморроем на стороне телефона и не все в него умеют

+ Не нужен никакой sock5-прокси на VPS с передачей паролей открытым текстом

+ Даже если к VPS прицепится миллион левых клиентов - она не «ляжет» сама по себе, поскольку там нагружать нечего

Недостаток подхода:

- пробитую дыру-портал в телегу всё равно легко засниффить, как минимум по IP-адресу назначения трафика, серверу socks5 telegram - и тогда можно использовать трафик на чужой VPS-ке для своего подключения.

- если всё-таки к VPS прицепятся «пьявки» в огромном количестве, то заметить это будет трудно, из-за чего легко будет просадить весь месяный трафик

Повторюсь, почему VPN и sock5 плохо:

1) VPN - жрёт батарейку и вроде бы на нерутованных телефонах с ним проблемы. Плюс виртуалка с KVM/vmware дороже, чем OpenVZ

2) Sock5 - вообще треш: ты либо открываешь прокси всему миру, либо соглашашеься на то, что пароли будут ходить открытым текстом, и в итоге твой прокси всё равно будет открыт всему миру

 ,

DRVTiny ()

Можно ли ограничить доступ не по IP к socks5-прокси?

Форум — Admin

Не смог найти ответ на этот каверзный вопрос. В настройках подключения телеги к Socks5 есть поля для аутентификации, в настройках же самого tor (torrc) не находится ничего подобного, только для доступа на control port.

Я что-то пропустил? Как ограничить доступ на tor только для тех, кто знает что-нибудь секретное?

 

DRVTiny ()

Посоветуйте зарубежную VPS-платформу

Форум — Talks

Хочу купить виртуалку зарубежом. Недорогую, не слишком мощную, желательно с хорошим интернет-каналом. Обязательно с белым IP-адресом.

Посмотрел hetzner - там что-то ппц дорого стало или я не туда смотрю.

Amazon принципиально не хочу, хайповая хрень какая-то.

Какие ещё есть интересные варианты?

 

DRVTiny ()

Поиск файлов perl-пакетов и выполнение действия для каждого из них

Форум — Development

Собственно, накатал функцию для означенной надобности: например, найти файлы пакетов Digest::MD5, File::Map и выполнить fgrep VERSION на каждом из них:

PerlSrch_Pkg Digest::MD5 File::Map -- fgrep VERSION

Код функции:

PerlSrch_Pkg () {
  local -a lstPkgNames lstPerlINC
  local arg rxPkgNames
  
  [[ $@ ]] || return 1
  while (($#)); do
    arg=$1; shift
    if [[ $arg == '--' ]]; then
      break
    else
      lstPkgNames+=("${arg//::/\/}")
    fi
  done
  rxPkgNames="("$(declare -p lstPkgNames | sed -r -e 's%^.+\[0\]="%[0]="%' -e 's%\s*\[[0-9]+\]="([^"]+)"%\1|%g' -e "s%\)'$%%" -e 's%\|$%%')")"
  
  readarray -t lstPerlINC < <(perl -e 'print join(qq|\n|  => grep { !/^\.$/ and -d $_ } @INC),"\n"')
  
  find "${lstPerlINC[@]}" \
  	-maxdepth 2 \
  	-type f \
  	-regextype posix-extended -regex ".*/${rxPkgNames}\.pm" \
  	$((($#)) && echo "-exec $@ {} ;" || echo '')
}

Пример «утилиты» perlpf (perl-package-finder), использующей оную функцию:

#!/bin/bash

source ${0%/*}/../perl.inc
pkgName=$1; shift
PerlSrch_Pkg $pkgName ${@:+-- $@}

Актуальную версию этой функции и другие полезные маленькие библиотеки для bash можно посмотреть здесь: https://github.com/DRVTiny/bash4-debug-infra

 ,

DRVTiny ()

Какой вариант расшаривания большого и толстого хеша вы бы предпочли и почему?

Форум — Development

Что-то вроде опроса среди перловодов :)

Хинт: Структура данных периодически (от раза в 15 секунд до раза в 10 минут) изменяется. Размер структуры данных незначительно, но тоже изменяется. Процессы все в рамках одной машины. Но нет, это не процессы в рамках Apache/mod_perl. «Потребители» читают структуру данных целиком, а потом просто получают её апдейты, поэтому хранить её как-то по частям нет никакого смысла.

Варианты ответов:

1) Засунул бы в ключ NoSQL'я (Redis/Tarantool/MongoDB), засериализовав её в JSON/CBOR/BSON/MessagePack и т.д. - нехай кому надо get'ом забирают.

2) Засунул бы в IPC Shared Memory, пусть из оперативы без посредников качают и десериализуют всё как надо

3) Поднял бы сокет UNIX/TCP - и отдавал бы сериализованное всем желающим по запросу

4) Использовал бы какие-нибудь варианты наподобие очередей и b(lpop) в Redis для организации своеобразного RPC на базе NoSQL-ки

5) Использовал бы File::Map или подобные mmap-штуки, сделав файл изначально процентов на 20 больше сериализованной структуры, чтобы учитывать даже самые зверские флуктуации её размера (как тогда «подрезать» считанное из map'а до реального размера, чтобы десериализовать?)

Лично мне милы варианты 1 и 5. А вам?

«Спасибо за внимание, дети мои, с вами был я, Три-дог-найт, на волне вашего любимого Радио, Новости Галактики!» (С)

 ,

DRVTiny ()

Как безопасно заполнить value для option?

Форум — Development

Достаточно ли в select.option.value экранировать «\» все одинарные и двойные кавычки, а также сам «\»?

Т.е., например, хватит ли перловой функции quotemeta?

Спасибо!

P.S. Прошу прощения за то, что ошибся раздел форума - есть Web-development рядом, просто промахнулся.

 ,

DRVTiny ()

Как отличить аргумент-константу от аргумента-переменной?

Форум — Development

How on the Earth...

Давайте, не мудрствуя лукаво, рассмотрим пример кода, в котором немного не достаёт функционала одной проверки:

sub f {
  my $refStr=\$_[0];
  return if passed_as_constant($_[0]) and !defined(wantarray);
  substr(${$refStr}, 0, 1)='D';
# return the copy of the string if it was passed
# to the function as constant aka "literally" or if copying was explicitly requested by the left-side context
  (passed_as_constant($_[0]) or defined(wantarray)) and return ${$refStr};
}
# Argument was passed literally and function called without left-side context - we may simply "do nothing"
f('Bingo!');

# Argument was passed literally and left-side context is here. We must return a copy of literal/constant
say my $s=f('Bingo!');

# Here we can modify the $s "in-place"
f(my $s='Bingo!');

Собственно, вопрос: как (on the Earth) реализовать вот это самое passed_as_constant? :)

ОТВЕТ:

use Scalar::Util qw(readonly);
{ no strict 'refs'; *{'main::passed_as_constant'}=\&readonly; }

 , , ,

DRVTiny ()

<Proxy> не понимает дополнительные параметры при использовании mod_proxy_fcgi

Форум — Admin

Настроил Apachе 2.4 в связке с php-fpm по оф.мануалам, вроде бы всё ОК, но смущает то, что пришлось закомментировать вот этот кусок конфигурации, описанный как в руководстве mod_proxy_fcgi, так и в руководстве на сайте php-fpm ( https://httpd.apache.org/docs/2.4/mod/mod_proxy_fcgi.html и https://wiki.apache.org/httpd/PHP-FPM )

Этот кусок пришлось убрать:

<Proxy "fcgi://localhost:9000/" enablereuse=on max=10>
</Proxy>

И всё потому что Апач на этот кусок конфигурации жалуется следующим образом:

AH00526: Syntax error on line ...

Целиком конфигурация связки с php-fpm вставлена в VirtualHost и выглядит точно так же, как и в мануалах:

<FilesMatch "\.php$">

    <If "-f %{REQUEST_FILENAME}">

        # Pick one of the following approaches

        # Use the standard TCP socket

        SetHandler "proxy:fcgi://localhost/:9000"

        # If your version of httpd is 2.4.9 or newer (or has the back-ported feature), you can use the unix domain socket

        #SetHandler "proxy:unix:/path/to/app.sock|fcgi://localhost/"

    </If>

</FilesMatch>

<Proxy "fcgi://localhost:9000/" enablereuse=on max=10>
</Proxy>

Посмотрел мануал по секции «Proxy» -там конечно вообще нет упоминаний «enablereuse» и «max».

Теперь меня мучает вопрос: что я сделал не так? :)

Подскажите, если кто в курсе настройки Apache + PHP-FPM

 , ,

DRVTiny ()

RSS подписка на новые темы