Newer
Older
///////////////////////////////////////////////////////////////////////////////////////////////////
// Прикладной интерфейс
Перем мНастройки;
Перем Лог;
Перем мИдентификаторКластера;
Перем ЭтоWindows;
Процедура ЗарегистрироватьКоманду(Знач ИмяКоманды, Знач Парсер) Экспорт
ОписаниеКоманды = Парсер.ОписаниеКоманды(ИмяКоманды, "Управление сеансами информационной базы");
Сосна Евгений
committed
Парсер.ДобавитьПозиционныйПараметрКоманды(ОписаниеКоманды, "Действие", "lock|unlock|kill");
Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды, "-ras", "Сетевой адрес RAS, по умолчанию localhost:1545");
Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды, "-rac", "Команда запуска RAC, по умолчанию находим в каталоге установки 1с");
Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды, "-db", "Имя информационной базы");
Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды,
"-db-user",
"Пользователь информационной базы");
Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды,
"-db-pwd",
"Пароль пользователя информационной базы");
Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды,
"-cluster-admin",
"Администратор кластера");
Сосна Евгений
committed
Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды,
"-cluster-pwd",
"Пароль администратора кластера");
Сосна Евгений
committed
Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды,
"-v8version",
"Маска версии платформы 1С");
Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды,
"-lockmessage",
"Сообщение блокировки");
Сосна Евгений
committed
Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды,
"-lockuccode",
"Ключ разрешения запуска");
Сосна Евгений
committed
Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды,
"-lockstart",
"Время старта блокировки пользователей, время указываем как '2040-12-31T23:59:59'");
Сосна Евгений
committed
Парсер.ДобавитьИменованныйПараметрКоманды(ОписаниеКоманды,
"-lockstartat",
"Время старта блокировки через n сек");
Парсер.ДобавитьКоманду(ОписаниеКоманды);
КонецПроцедуры
Функция ВыполнитьКоманду(Знач ПараметрыКоманды) Экспорт
ПрочитатьПараметры(ПараметрыКоманды);
Если Не ПараметрыВведеныКорректно() Тогда
Возврат МенеджерКомандПриложения.РезультатыКоманд().НеверныеПараметры;
КонецЕсли;
Если мНастройки.Действие = "lock" Тогда
УстановитьСтатусБлокировкиСеансов(Истина);
ИначеЕсли мНастройки.Действие = "unlock" Тогда
УстановитьСтатусБлокировкиСеансов(Ложь);
ИначеЕсли мНастройки.Действие = "kill" Тогда
УдалитьВсеСеансыИСоединенияБазы();
Иначе
Лог.Ошибка("Неизвестное действие: " + мНастройки.Действие);
Возврат МенеджерКомандПриложения.РезультатыКоманд().НеверныеПараметры;
КонецЕсли;
Возврат МенеджерКомандПриложения.РезультатыКоманд().Успех;
КонецФункции
Процедура ПрочитатьПараметры(Знач ПараметрыКоманды)
мНастройки = Новый Структура;
Для Каждого КЗ Из ПараметрыКоманды Цикл
Лог.Отладка(КЗ.Ключ + " = " + КЗ.Значение);
КонецЦикла;
мНастройки.Вставить("АдресСервераАдминистрирования", ПараметрыКоманды["-ras"]);
мНастройки.Вставить("ПутьКлиентаАдминистрирования", ПараметрыКоманды["-rac"]);
мНастройки.Вставить("ИмяБазыДанных", ПараметрыКоманды["-db"]);
мНастройки.Вставить("АдминистраторИБ", ПараметрыКоманды["-db-user"]);
мНастройки.Вставить("ПарольАдминистратораИБ", ПараметрыКоманды["-db-pwd"]);
мНастройки.Вставить("АдминистраторКластера", ПараметрыКоманды["-cluster-admin"]);
мНастройки.Вставить("ПарольАдминистратораКластера", ПараметрыКоманды["-cluster-pwd"]);
Сосна Евгений
committed
мНастройки.Вставить("ИспользуемаяВерсияПлатформы", ПараметрыКоманды["-v8version"]);
мНастройки.Вставить("КлючРазрешенияЗапуска", ПараметрыКоманды["-lockuccode"]);
мНастройки.Вставить("СообщениеОблокировке", ПараметрыКоманды["-lockmessage"]);
мНастройки.Вставить("ВремяСтратаБлокировки", ПараметрыКоманды["-lockstart"]);
мНастройки.Вставить("ВремяСтратаБлокировкиЧерез", ПараметрыКоманды["-lockstartat"]);
мНастройки.Вставить("Действие", ПараметрыКоманды["Действие"]);
Сосна Евгений
committed
//Получим путь к платформе если вдруг не установленна
мНастройки.ПутьКлиентаАдминистрирования = ПолучитьПутьКRAC(мНастройки.ПутьКлиентаАдминистрирования, мНастройки.ИспользуемаяВерсияПлатформы);
Если ПустаяСтрока(мНастройки.АдресСервераАдминистрирования) Тогда
мНастройки.АдресСервераАдминистрирования = "localhost:1545";
КонецЕсли;
КонецПроцедуры
Функция ПараметрыВведеныКорректно()
Успех = Истина;
Если Не ЗначениеЗаполнено(мНастройки.АдресСервераАдминистрирования) Тогда
Лог.Ошибка("Не указан сервер администрирования");
Успех = Ложь;
КонецЕсли;
Если Не ЗначениеЗаполнено(мНастройки.ПутьКлиентаАдминистрирования) Тогда
Лог.Ошибка("Не указан клиент администрирования");
Успех = Ложь;
КонецЕсли;
Если Не ЗначениеЗаполнено(мНастройки.ИмяБазыДанных) Тогда
Лог.Ошибка("Не указано имя базы данных");
Успех = Ложь;
КонецЕсли;
Если Не ЗначениеЗаполнено(мНастройки.Действие) Тогда
Лог.Ошибка("Не указано действие lock/unlock");
Успех = Ложь;
КонецЕсли;
Возврат Успех;
КонецФункции
/////////////////////////////////////////////////////////////////////////////////
// Взаимодействие с кластером
Процедура УдалитьВсеСеансыИСоединенияБазы()
УстановитьСтатусБлокировкиСеансов(Истина);
ОтключитьСуществующиеСеансы();
Приостановить(500);
Сеансы = ПолучитьСписокСеансов();
Если Сеансы.Количество() Тогда
Лог.Информация("Пауза перед отключением соединений");
Приостановить(10000);
ОтключитьСоединенияСРабочимиПроцессами();
КонецПроцедуры
Процедура УстановитьСтатусБлокировкиСеансов(Знач Блокировать)
КлючиАвторизацииВБазе = КлючиАвторизацииВБазе();
Сосна Евгений
committed
ИдентификаторКластера = ИдентификаторКластера();
ИдентификаторБазы = ИдентификаторБазы();
Artur Ayukhanov
committed
Если Блокировать Тогда
КлючРазрешенияЗапускаПоУмолчанию = ИдентификаторБазы;
Иначе
КлючРазрешенияЗапускаПоУмолчанию = "";
КонецЕсли;
КлючРазрешенияЗапуска = ?(ПустаяСтрока(мНастройки.КлючРазрешенияЗапуска), КлючРазрешенияЗапускаПоУмолчанию, мНастройки.КлючРазрешенияЗапуска);
Сосна Евгений
committed
ВремяБлокировки = мНастройки.ВремяСтратаБлокировки;
Если ПустаяСтрока(ВремяБлокировки) И Не ПустаяСтрока(мНастройки.ВремяСтратаБлокировкиЧерез) Тогда
Секунды = 0;
Попытка
Секунды = Число(мНастройки.ВремяСтратаБлокировкиЧерез);
Исключение
КонецПопытки;
Сосна Евгений
committed
ВремяБлокировки = Формат(ТекущаяДата()+Секунды,"ДФ='yyyy-MM-ddTHH:mm:ss'");
Сосна Евгений
committed
КонецЕсли;
КомандаВыполнения = СтрокаЗапускаКлиента() + СтрШаблон("infobase update --infobase=""%3""%4 --cluster=""%1""%2 --sessions-deny=%5 --denied-message=""%6"" --denied-from=""%8"" --permission-code=""%7""",
ИдентификаторКластера,
КлючиАвторизацииВКластере(),
ИдентификаторБазы,
КлючиАвторизацииВБазе,
?(Блокировать, "on", "off"),
Сосна Евгений
committed
мНастройки.СообщениеОблокировке,
КлючРазрешенияЗапуска,
ВремяБлокировки) + " "+мНастройки.АдресСервераАдминистрирования;
ЗапуститьПроцесс(КомандаВыполнения);
Лог.Информация("Сеансы " + ?(Блокировать, "запрещены", "разрешены"));
Функция КлючиАвторизацииВБазе()
КлючиАвторизацииВБазе = "";
Если ЗначениеЗаполнено(мНастройки.АдминистраторИБ) Тогда
КлючиАвторизацииВБазе = КлючиАвторизацииВБазе + СтрШаблон(" --infobase-user=""%1""", мНастройки.АдминистраторИБ);
КонецЕсли;
Если ЗначениеЗаполнено(мНастройки.ПарольАдминистратораИБ) Тогда
КлючиАвторизацииВБазе = КлючиАвторизацииВБазе + СтрШаблон(" --infobase-pwd=""%1""", мНастройки.ПарольАдминистратораИБ);
КонецЕсли;
Возврат КлючиАвторизацииВБазе;
КонецФункции
Если мИдентификаторКластера = Неопределено Тогда
Лог.Информация("Получаю список кластеров");
КомандаВыполнения = СтрокаЗапускаКлиента() + "cluster list" + " "+мНастройки.АдресСервераАдминистрирования;
СписокКластеров = ЗапуститьПроцесс(КомандаВыполнения);
УИДКластера = Сред(СписокКластеров,(Найти(СписокКластеров,":")+1),Найти(СписокКластеров,"host")-Найти(СписокКластеров,":")-1);
мИдентификаторКластера = СокрЛП(СтрЗаменить(УИДКластера,Символы.ПС,""));
КонецЕсли;
Если ПустаяСтрока(мИдентификаторКластера) Тогда
ВызватьИсключение "Кластер серверов отсутствует";
КонецЕсли;
Возврат мИдентификаторКластера;
Если мИдентификаторБазы = Неопределено Тогда
мИдентификаторБазы = НайтиБазуВКластере();
КонецЕсли;
Возврат мИдентификаторБазы;
КомандаВыполнения = СтрокаЗапускаКлиента() + СтрШаблон("infobase summary list --cluster=""%1""%2",
ИдентификаторКластера(),
КлючиАвторизацииВКластере()) + " "+мНастройки.АдресСервераАдминистрирования;
Лог.Информация("Получаю список баз кластера");
СписокБазВКластере = СокрЛП(ЗапуститьПроцесс(КомандаВыполнения));
Лог.Отладка(СписокБазВКластере);
ЧислоСтрок = СтрЧислоСтрок(СписокБазВКластере);
НайденаБазаВКластере = Ложь;
Для К = 1 По ЧислоСтрок Цикл
СтрокаРазбора = СтрПолучитьСтроку(СписокБазВКластере,К);
ПозицияРазделителя = Найти(СтрокаРазбора,":");
Если Найти(СтрокаРазбора,"infobase")>0 Тогда
УИДИБ = СокрЛП(Сред(СтрокаРазбора,ПозицияРазделителя+1));
ИначеЕсли Найти(СтрокаРазбора,"name")>0 Тогда
ИмяБазы = СокрЛП(Сред(СтрокаРазбора,ПозицияРазделителя+1));
Сосна Евгений
committed
Если Нрег(ИмяБазы) = НРег(мНастройки.ИмяБазыДанных) Тогда
Лог.Информация("Получен УИД базы");
НайденаБазаВКластере = Истина;
Прервать;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Если Не НайденаБазаВКластере Тогда
ВызватьИсключение "База "+мНастройки.ИмяБазыДанных +" не найдена в кластере";
КомандаВыполнения = "";
Если ЗначениеЗаполнено(мНастройки.АдминистраторКластера) Тогда
КомандаВыполнения = КомандаВыполнения + СтрШаблон(" --cluster-user=""%1""", мНастройки.АдминистраторКластера);
КонецЕсли;
Если ЗначениеЗаполнено(мНастройки.ПарольАдминистратораКластера) Тогда
КомандаВыполнения = КомандаВыполнения + СтрШаблон(" --cluster-pwd=""%1""", мНастройки.ПарольАдминистратораКластера);
КонецЕсли;
Возврат КомандаВыполнения;
Перем ПутьКлиентаАдминистрирования;
Если ЭтоWindows Тогда
ПутьКлиентаАдминистрирования = ЗапускПриложений.ОбернутьВКавычки(мНастройки.ПутьКлиентаАдминистрирования);
Иначе
ПутьКлиентаАдминистрирования = мНастройки.ПутьКлиентаАдминистрирования;
КонецЕсли;
Возврат ПутьКлиентаАдминистрирования + " ";
Функция ЗапуститьПроцесс(Знач СтрокаВыполнения)
Перем ПаузаОжиданияЧтенияБуфера;
Процесс = СоздатьПроцесс(СтрокаВыполнения,,Истина);
Текст = Новый ТекстовыйДокумент;
Пока Истина Цикл
ВывестиДанныеПроцесса(Процесс, Текст);
Если Процесс.Завершен Тогда
Процесс.ОжидатьЗавершения(); // финальный сброс буферов
ВывестиДанныеПроцесса(Процесс, Текст);
Прервать;
КонецЕсли;
Приостановить(ПаузаОжиданияЧтенияБуфера);
Иначе
ВызватьИсключение "Сообщение от RAS/RAC
Процедура ВывестиДанныеПроцесса(Знач Процесс, Знач Приемник)
Вывод = Процесс.ПотокВывода.Прочитать();
Ошибки = Процесс.ПотокОшибок.Прочитать();
Если СтрДлина(Строка(Вывод)) > 0 Тогда
Приемник.ДобавитьСтроку(Вывод);
КонецЕсли;
Если СтрДлина(Строка(Ошибки)) > 0 Тогда
Приемник.ДобавитьСтроку(Ошибки);
КонецЕсли;
КонецПроцедуры
Процедура ОтключитьСуществующиеСеансы()
Лог.Информация("Отключаю существующие сеансы");
СеансыБазы = ПолучитьСписокСеансов();
Для Каждого Сеанс Из СеансыБазы Цикл
Сосна Евгений
committed
Попытка
ОтключитьСеанс(Сеанс);
Исключение
Лог.Ошибка(ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Функция ПолучитьСписокСеансов()
ТаблицаСеансов = Новый ТаблицаЗначений;
ТаблицаСеансов.Колонки.Добавить("Идентификатор");
ТаблицаСеансов.Колонки.Добавить("Приложение");
ТаблицаСеансов.Колонки.Добавить("Пользователь");
ТаблицаСеансов.Колонки.Добавить("НомерСеанса");
КомандаЗапуска = СтрокаЗапускаКлиента() + СтрШаблон("session list --cluster=""%1""%2 --infobase=""%3""",
ИдентификаторКластера(),
КлючиАвторизацииВКластере(),
ИдентификаторБазы()) + " " + мНастройки.АдресСервераАдминистрирования;
СписокСеансовИБ = ЗапуститьПроцесс(КомандаЗапуска);
Данные = РазобратьПоток(СписокСеансовИБ);
Для Каждого Элемент Из Данные Цикл
ТекСтрока = ТаблицаСеансов.Добавить();
ТекСтрока.Идентификатор = Элемент["session"];
ТекСтрока.Пользователь = Элемент["user-name"];
ТекСтрока.Приложение = Элемент["app-id"];
ТекСтрока.НомерСеанса = Элемент["session-id"];
КонецФункции
Процедура ОтключитьСеанс(Знач Сеанс)
СтрокаВыполнения = СтрокаЗапускаКлиента() + СтрШаблон("session terminate --cluster=""%1""%2 --session=""%3""",
ИдентификаторКластера(),
КлючиАвторизацииВКластере(),
Сеанс.Идентификатор) + " " +мНастройки.АдресСервераАдминистрирования;
Лог.Информация(СтрШаблон("Отключаю сеанс: %1 [%2] (%3)", Сеанс.НомерСеанса, Сеанс.Пользователь, Сеанс.Приложение));
Сосна Евгений
committed
ЗапуститьПроцесс(СтрокаВыполнения);
Функция ОтключитьСоединенияСРабочимиПроцессами()
Процессы = ПолучитьСписокРабочихПроцессов();
Для Каждого РабочийПроцесс Из Процессы Цикл
Если РабочийПроцесс["running"] = "yes" Тогда
СписокСоединений = ПолучитьСоединенияРабочегоПроцесса(РабочийПроцесс);
Для Каждого Соединение Из СписокСоединений Цикл
Попытка
РазорватьСоединениеСПроцессом(РабочийПроцесс, Соединение);
Исключение
Лог.Ошибка(ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
КонецЕсли;
КонецЦикла;
КонецФункции
Функция ПолучитьСписокРабочихПроцессов()
КомандаЗапускаПроцессы = СтрокаЗапускаКлиента() + СтрШаблон("process list --cluster=""%1""%2",
ИдентификаторКластера(),
КлючиАвторизацииВКластере()) + " "+мНастройки.АдресСервераАдминистрирования;
Лог.Информация("Получаю список рабочих процессов...");
СписокПроцессов = ВыполнитьКоманду(КомандаЗапускаПроцессы);
Возврат РазобратьПоток(СписокПроцессов);
КонецФункции
Функция ПолучитьСоединенияРабочегоПроцесса(Знач РабочийПроцесс)
КомандаЗапускаСоединения = СтрокаЗапускаКлиента() + СтрШаблон("connection list --cluster=""%1""%2 --infobase=%3%4 --process=%5",
ИдентификаторКластера(),
КлючиАвторизацииВКластере(),
ИдентификаторБазы(),
КлючиАвторизацииВБазе(),
РабочийПроцесс["process"]) + " "+мНастройки.АдресСервераАдминистрирования;
Лог.Информация("Получаю список соединений...");
Возврат РазобратьПоток(ВыполнитьКоманду(КомандаЗапускаСоединения));
КонецФункции
Функция РазорватьСоединениеСПроцессом(Знач РабочийПроцесс, Знач Соединение)
КомандаРазрывСоединения = СтрокаЗапускаКлиента() + СтрШаблон("connection disconnect --cluster=""%1""%2 --infobase=%3%4 --process=%5 --connection=%6",
ИдентификаторКластера(),
КлючиАвторизацииВКластере(),
ИдентификаторБазы(),
КлючиАвторизацииВБазе(),
РабочийПроцесс["process"],
Соединение["connection"])+ " "+мНастройки.АдресСервераАдминистрирования;
Сообщение = СтрШаблон("Отключаю соединение %1 [%2] (%3)",
Соединение["conn-id"],
Соединение["app-id"],
Соединение["user-name"]);
Лог.Информация(Сообщение);
Возврат ВыполнитьКоманду(КомандаРазрывСоединения);
КонецФункции
Функция РазобратьПоток(Знач Поток) Экспорт
ТД = Новый ТекстовыйДокумент;
ТД.УстановитьТекст(Поток);
СписокОбъектов = Новый Массив;
ТекущийОбъект = Неопределено;
Для Сч = 1 По ТД.КоличествоСтрок() Цикл
Текст = ТД.ПолучитьСтроку(Сч);
Если ПустаяСтрока(Текст) или ТекущийОбъект = Неопределено Тогда
Если ТекущийОбъект <> Неопределено и ТекущийОбъект.Количество() = 0 Тогда
Продолжить; // очередная пустая строка подряд
КонецЕсли;
ТекущийОбъект = Новый Соответствие;
СписокОбъектов.Добавить(ТекущийОбъект);
КонецЕсли;
СтрокаРазбораИмя = "";
СтрокаРазбораЗначение = "";
Если РазобратьНаКлючИЗначение(Текст, СтрокаРазбораИмя, СтрокаРазбораЗначение) Тогда
ТекущийОбъект[СтрокаРазбораИмя] = СтрокаРазбораЗначение;
КонецЕсли;
КонецЦикла;
Если ТекущийОбъект <> Неопределено и ТекущийОбъект.Количество() = 0 Тогда
СписокОбъектов.Удалить(СписокОбъектов.ВГраница());
КонецЕсли;
Возврат СписокОбъектов;
КонецФункции
Сосна Евгений
committed
Функция ПолучитьПутьКRAC(ТекущийПуть, Знач ВерсияПлатформы="")
Если НЕ ПустаяСтрока(ТекущийПуть) Тогда
ФайлУтилиты = Новый Файл(ТекущийПуть);
Если ФайлУтилиты.Существует() Тогда
Лог.Отладка("Текущая версия rac "+ФайлУтилиты.ПолноеИмя);
Возврат ФайлУтилиты.ПолноеИмя;
КонецЕсли;
КонецЕсли;
Если ПустаяСтрока(ВерсияПлатформы) Тогда
ВерсияПлатформы="8.3";
КонецЕсли;
Конфигуратор = Новый УправлениеКонфигуратором;
ПутьКПлатформе = Конфигуратор.ПолучитьПутьКВерсииПлатформы(ВерсияПлатформы);
Лог.Отладка("Используемый путь для поиска rac "+ПутьКПлатформе);
КаталогУстановки = Новый Файл(ПутьКПлатформе);
Лог.Отладка(КаталогУстановки.Путь);
Сосна Евгений
committed
ИмяФайла = ?(ЭтоWindows, "rac.exe", "rac");
ФайлУтилиты = Новый Файл(ОбъединитьПути(Строка(КаталогУстановки.Путь), ИмяФайла));
Если ФайлУтилиты.Существует() Тогда
Лог.Отладка("Текущая версия rac "+ФайлУтилиты.ПолноеИмя);
Возврат ФайлУтилиты.ПолноеИмя;
КонецЕсли;
Возврат ТекущийПуть;
КонецФункции
Функция РазобратьНаКлючИЗначение(Знач СтрокаРазбора, Ключ, Значение)
ПозицияРазделителя = Найти(СтрокаРазбора,":");
Если ПозицияРазделителя = 0 Тогда
Возврат Ложь;
КонецЕсли;
Ключ = СокрЛП(Лев(СтрокаРазбора,ПозицияРазделителя-1));
Значение = СокрЛП(Сред(СтрокаРазбора,ПозицияРазделителя+1));
Возврат Истина;
КонецФункции
/////////////////////////////////////////////////////////////////////////////////
СистемнаяИнформация = Новый СистемнаяИнформация;
ЭтоWindows = Найти(НРег(СистемнаяИнформация.ВерсияОС), "windows") > 0;
Лог = Логирование.ПолучитьЛог("vanessa.app.deployka");