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

Публикация № 609568

Администрирование - Распределенная БД (УРИБ, УРБД)

автоматизация обновление скрипт

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

Первым делом настроили РБД таким образом, что в регионах остались подчиненные узлы, а в едином центре - главные (делалось это конечно не только ради обновления  - иначе можно было бы попробовать и другие варианты, без УРБД). Главные узлы подключили к единому хранилищу. Однако обновлять десять баз, даже при наличии хранилища - занятие довольно "муторное". Поднимаем вопрос пакетного режима конфигуратора:

REM ------------- Обновление базы из хранилища (cmd) -----------------------
 
set bin = "C:\Program Files (x86)\1cv8\8.3.9.2170\bin\1cv8.exe"
set Srvr = srv
set Base = infobase
set Name = Admin
set Pass = pass
set Repo = tcp://srv/conf
set Code = GoD
set Log = D:\auto\logs\log_%date:~0,2%%date:~3,2%%date:~6,4%.txt
 
%bin% DESIGNER /S"%Srvr%/%Base%" /N%Name% /P%Pass% /ConfigurationRepositoryF%Repo% /ConfigurationRepositoryN%Base% /ConfigurationRepositoryUpdateCfg /UC%Code% /OUT%Log% -NoTruncate

REM ---------------- Обновление базы данных (cmd) --------------------------
 
set bin = "C:\Program Files (x86)\1cv8\8.3.9.2170\bin\1cv8.exe"
set Srvr = srv
set Base = infobase
set Name = Admin
set Pass = pass
set Code = GoD
set Log = D:\auto\logs\log_%date:~0,2%%date:~3,2%%date:~6,4%.txt
 
%bin% DESIGNER /S"%Srvr%/%Base%" /N%Name% /P%Pass% /UpdateDBCfg -Server /UC%Code% /OUT%Log% -NoTruncate
 

Уже неплохо! Написать bat/cmd файлик, который сделает это для десятка баз - не составляет труда... Если бы не одно "но" - все это нужно делать в "монопольном" режиме, т.е. когда в системе/системах нет пользователей. Как выгонять пользователей из клиент-серверной 1С? Скриптом! vbs, например:  

'----------------------- Закрыть все соединения с конкретной базой (vbs) ---------------------------
  Set ComConnector = CreateObject("v83.ComConnector")'это, по сути, консоль кластера
  Set ServerAgent = ComConnector.ConnectAgent("srv")' вернее вот это
  Clasters = ServerAgent.GetClusters()
  For Each Claster In Clasters
    ServerAgent.Authenticate Claster, ClasterAdminName, ClasterAdminPass 
    'Как не странно неинициализированные значения прокатывают, если на кластере нет авторизации
    Sessions = ServerAgent.GetSessions(Claster)
    For Each Session In Sessions
      If Session.InfoBase.Name = "infobase" Then
        Call ServerAgent.TerminateSession(Claster,Session)
      End If
    Next
    Exit For
  Next
 
'----------------------- Запретить соединения с конкретной базой (vbs) -----------------------------
  Set ComConnector = CreateObject("v83.ComConnector")
  Set ServerAgent = ComConnector.ConnectAgent("srv")
  Clasters = ServerAgent.GetClusters()
  For Each Claster In Clasters
    ServerAgent.Authenticate Claster, ClasterAdminName, ClasterAdminPass
    WorkingProcesses = ServerAgent.GetWorkingProcesses(Claster)
    For Each WorkingProcess In WorkingProcesses 'чуток сложнее, нужно подключение к рабочему процессу...
      If WorkingProcess.Running = 1 Then
        Set connecttoworkprocess = ComConnector.ConnectWorkingProcess("tcp://" + WorkingProcess.HostName + ":" + CStr(WorkingProcess.MainPort))
        connecttoworkprocess.AddAuthentication "Admin", "pass"
        'а здесь уже нужны реальные логин/пароль к конкретной базе
        InfoBases = connecttoworkprocess.GetInfoBases()
        For Each InfoBase In InfoBases
          If InfoBase.Name = "infobase" Then
            InfoBase.ConnectDenied = True
            InfoBase.DeniedFrom = CStr(Now())
            InfoBase.DeniedTo = CStr(Now() + 1 / 24 * 3)
            InfoBase.DeniedMessage = "База заблокированна администратором!"
            InfoBase.PermissionCode = "GoD"
            connecttoworkprocess.UpdateInfoBase (InfoBase)
            Exit For
          End If
        Next
        Exit For
      End If
    Next
    Exit For
  Next

Ну, т.е. мы сначала запрещаем соединения с базой (не забыв при этом установить код разрешения), потом обрываем существующие сессии пользователей, потом обновляем конфигурацию из хранилища и конфигурацию базы данных (указывая установленный ранее код разрешения)... Разрешить работу с базами после этого не сложнее, чем запретить, просто в строке InfoBase.ConnectDenied = True меняем на False (и при желании очищаем остальные поля).  

Все это хорошо, но у нас базы распределенные. В принципе изменения в удаленные базы уйдут с ближайшим обменом по расписанию, но мы можем сделать это и принудительно, причем способов у нас несколько (речь идет об относительно типовой конфигурации, где присутствуют стандартные настройки УРБД):

  1.  Настроить автоматический обмен по событию - при входе определенного пользователя в систему. Тогда нам просто достаточно запустить 1С под этим пользователем.
  2. Можем использовать параметр командной строки /Execute для запуска обработки в которой может быть прописано что угодно, включая вызов экспортной процедуры общего модуля для запуска обмена. 
  3. Или можем использовать vbs скрипт в тех же целях:

'------------------- Выполнить экспортную процедуру общего модуля (vbs) ------------------------------
  Set Base = CreateObject("V83.Application")
  Base.Connect("Srvr='srv';Ref='infobase';Usr=Admin;Pwd=pass;UC=GoD")'Стандартная строка соединения 1С 
  Base.[МодульРегламентныхЗаданий].[ВыполнитьОбменДаннымиДляНастройкиАвтоматическогоОбменаДанными]("000001")
  'Для того, что бы свободно использовать кириллицу, нужны квадратные скобки
 

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

  • Нестабильные каналы и разные часовые пояса превращают расчет этого самого "запаса" в непростой квест. 
  • Базы а регионе далеко не всегда работают в клиент-серверном режиме, есть и файловые. А значит, выгнать пользователей этим скриптом не получится. 
  • Хотелось бы иметь инструмент, позволяющий запустить принудительное обновление, не в конкретно заданное время, а в любой момент, т.е. процедуры "здесь" и "там" должны быть связаны (выполнятся последовательно).

Зато имеются и положительные моменты (я же рассказываю о собственном конкретном опыте, а не об универсальном решении):

  • удаленные сервера доступны внутри единой сети;
  • пользователи удаленных площадок работают на терминалах, т.е. клиенты 1С запущены не на рабочих станциях, а на одном конкретном сервере.

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

Вообще типовые конфигурации 1С предоставляют условно "штатный" механизм завершения работы пользователей, который по задумке должен одинаково отрабатывать и в файловом и в клиент-серверном варианте работы (для установки нужно зайти в базу с параметром /CЗавершитьРаботуПользователей, для снятия /CРазрешитьРаботуПользователей). однако на деле мне показался этот метод не очень стабильным, а главное "тяжеловесным" (запускать целое приложение ради сравнительно элементарных действий не хочется)  и долгим (по факту 1С запускает обработчик ожидания, который пытается завершить сенсы, пока это у него в конце концов не получится). Вариант с vbs, описанный выше, неплохо зарекомендовал себя на клиент-серверных базах, но он не применим в файловом режиме ( нету объекта v83.ComConnector). Для файлового же режима пара "лайфхаков":

  • Заблокированна база или нет по факту определяется наличием либо отсутствием файлика 1Cv8.cdn в каталоге базы данных. Да, вот так все просто. :)  Содержимое файлика:
{1,00010101000000,00010101000000,"База заблокирована администратором","GoD",""}

 Где второй и третий "параметр" - дата начала блокировки и дата конца блокировки соответственно в формате ГГГГММДДччммсс. (вы всегда можете запустить вашу файловую базу с параметром /CЗавершитьРаботуПользователей, что бы получить этот файл и проанализировать его)

  • Команда taskkill прекрасно, хотя возможно излишне "сурово" завершает работу пользователей! :) в числе прочих ее параметров, есть /FI, который позволяет достаточно гибко настроить ,какие именно процессы надо завершать. Сейчас я остановился на варианте taskkill /f /FI "IMAGENAME eq 1cv8.exe", хотя в таком случае "безвинно пострадают" сеансы, не имеющие отношения к целевой базе (если таковые имеются). Я пробовал более "элегантный" вариант: taskkill /f /FI "WINDOWTITLE eq 1С:Предприятие - Рабочая база" (Где <Рабочая база> - заголовок окна программы заданный в настройках), но он работает только в идеальных условиях (например - не "убиваются" сеансы, когда пользователь запустил 1С, система дошла до ввода пароля и на этом - все).

Кроме того, несколько стандартных "граблей" на которые я наступал в процессе:

  • Пара слов о psexec. Формат вызова: psexec \\reg_srv -u username -p pass -c -f "reg_todo_t.bat". Вроде бы все понятно, но как обычно есть пара нюансов. Ключ -c копирует файл reg_todo_t.bat из каталога запуска psexec на удаленную машину перед исполнением. И копирует он его в системный каталог (system32, кажется). Поэтому ,если есть необходимость в каких-то дополнительных исполняемых файлах (например vbs), их нужно или предвариательно положить туда же, или первой строкой в reg_todo_t.bat устанавливать нужный рабочий каталог. 
  • Еще один важный момент. Особенностью cmd/bat файла является то, что вызвав запуск сторонней программы, он считает данную инструкцию выполненной и переходит к следующей. Нам же нужно обеспечить запуск всех наших действий СТРОГО последовательно (нет смысла запускать обновление, если еще не закончилась процедура завершения сеансов). Для этих целей нужно использовать конструкцию start /wait.
  • cmd/bat файлы имеют OEM кодировку. Кирилические шрифты (в сообщения логирования, например) при открытии файла в блокноте по умолчанию будут отображаться "кракозябрами". Переключаем шрифт на terminal.  

Ну, вроде бы все необходимое у нас есть.  План такой: 

  1. Блокируем доступ к центральной базе (база серверная, поэтому vbs)
  2. Завершаем сеансы пользователя (тоже самое - vbs)
  3. Обновляем конфигурацию из хранилища (cmd/bat пакетный режим конфигуратора)
  4. Обновляем конфигурацию базы данных (то же самое)
  5. Запускаем обмен (vbs)
  6. Снимаем блокировку базы (серверная база, поэтому vbs)
  7. Удаленно на региональном сервере запускаем bat/cmd/wsf (psexec) , в котором:
    1. блокируем доступ к базе (для файловых баз: файлик 1Cv8.cdn, для серверных см п.1, vbs)
    2. Завершаем сеансы (для файловых баз: taskkill, для серверных - vbs)
    3. Запускаем обмен (CreateObject("V83.Application") работает как для серверных, так и для файловых баз)
    4. Обновляем конфигурацию базы данных (см п.4, пакетный режим)
    5. Снимаем блокировку базы (файлик 1Cv8.cdn или vbs)

Пример всего этого (для гипотетической инфраструктуры) во вложении.

Описание вложения: 

  1. DoIt!.bat - запускает обновление центральной и переферийной баз из хранилища  tcp://srv/conf, в котором имя пользователя равно имени базы (infobase), без пароля. Так или иначе вызывает остальные файлы.
  2. users.vbs - скрипт, который выгоняет пользователей и устанавливает блокировку базы, либо снимает блокировку базы в зависимости от параметра (off|on).
  3. update.bat обновляет базу из хранилища и обновляет конфигурацию БД. 
  4. obmen.vbs - запускает экспортную процедуру общего модуля, инициализирующую обмен по существующей настройке УРБД.

Нюансы предполагаемой инфраструктуры:

  1. Предполагаем наличие в сети сервера srv, с базой ibfobase.
  2. Предполагается так же, что на стороне удаленной площадки есть сервер reg_srv, доступный по сети, на котором:
    •     - в папке C:\auto есть папка Logs и файл obmen.vbs
    •     - установлена 1с и база лежит в каталоге D:\1C_Bases\infobase
    •     - авторизация в базе настроена по авторизации операционной системы.
  3. Программа psexec.exe в поставку не входит, ее следует скачать отдельно.

Upd 18.04.2017

  1. В типовых 1С есть "прекрасная" процедура при начале работы системы: КонтрольВерсииКонфигурации.ПроверитьВерсиюКонфигурации();

Эта процедура, проверяет константу ДатаТекущейВерсии, и, если она на два или более месяца меньше текущей даты, выводит модальное окно о необходимости одновить конфигурацию... Это окно выходит внезависимости от того - запускается ли сеанс с параметрами /DisableStartupMessage и /AU- оно просто появляется и все. И ломает всю схему. Вариантов есть несколько... С точки зрения 1С, видимо, необходимо поддерживать актуальную конфигурацию. Для тех, у кого разрешены изменения конфигурации стоит закомментировать приведенную выше строчку кода в модуле обычного приложения. У кого не разрешены: Константы.ДатаТекущейВерсии.Установить(Дата('21000101')); т.е. ставим дату конфигурации на 2100 год... Но это нужно будет делать после каждого обновления.  

  1. При вызове экспортной процедуры с помощью vbs скрипта - в строке соединения не было параметра UC, что не давало ему запустится (т.к. на момент его запуска соединения с БД запрещены). Добавил по тексту и исправил пример во вложении. 
19

Скачать файлы

Наименование Файл Версия Размер
auto_update.zip
.zip 3,14Kb
18.04.17
7
.zip 3,14Kb 7 Скачать

См. также

Специальные предложения

Комментарии
Избранное Подписка Сортировка: Древо
1. Stepa86 980 12.04.17 14:46 Сейчас в теме
(0) Деплойку не смотрел? http://infostart.ru/webinars/564260/ Она в том числе умеет отрубать соединения через RAS
2. Nehc 18 12.04.17 16:42 Сейчас в теме
(1) Посмотрел - любопытная штука. Но... Не смотря на открытый код - все равно "вещь в себе". Не полезешь ведь, без острой необходимости, в код - будешь использовать как "черный ящик": работает - не трогай. А я больше на примере хотел показать ,что можно фактически "из командной строки" сделать с минимальным скриптингом...
3. Stepa86 980 12.04.17 17:08 Сейчас в теме
(2) С помощью деплойки можно в принципе код упростить сильно, не влезая во внутрянку https://gist.github.com/pumbaEO/9a52710dfa519c060dc45e9b81b9af5e
4. Nehc 18 12.04.17 17:43 Сейчас в теме
(3) О! Onescript... Не сразу заметил... os - это хорошо! ;) Но все же это все в моем понимании из другой области... Хороших инструментов много всяких разных, но хотелось бы уметь/иметь возможность сделать все без них.
5. Nehc 18 12.04.17 18:02 Сейчас в теме
(1) О! Нашел про RAS - вот этого не знал, спасибо!
7. vlkvlkvlk 9 13.04.17 14:42 Сейчас в теме
такая же задача стояла. решением получилось создание клиент-серверного варианта приложения для запуска скриптов обновления баз риб. см статья
плюсом прикрутили мониторинг бекапов, онлайн просмотр версии конфигурации\платформы. ну и запуск обновления в гетерогенной сетевой среде через psexec может не сработать (у нас филиальная сеть в разных городах, не объединенная в рамках одной локальной сети)
8. Nehc 18 13.04.17 17:58 Сейчас в теме
(7) да, у меня все тоже к тому шло... Рассматривал варианты и небольших сервисных баз на стороне регионов с доступом по веб-сервису (благо для этого клиент-сервер не нужен, достаточно апача) и интеграцию с инстаграм, но... Все это пока в виде разрозненных набросков. До реализации полноценной не дошло. А то, что тут изложил - работает, как не странно: изменения, которые сегодня вернули в хранилище - завтра с утра во всех базах появляются... Не долго правда: пару недель всего. Плюс в начале неделю косяки отлавливал! ;)
Оставьте свое сообщение