5 июн. 2016 г.

One Script to rule them all


Говорят, хороший программист должен быть ленивым. Больше думать, меньше писать, использовать готовый код. А так же автоматизировать некоторые свои рутинные ручные операции. В последнем случае можно использовать такие языки, как VBS, Python. Для самых "ленивых" 1С-ников, которые хотят автоматизироваться уже прямо сейчас, без изучения нового языка, существует проект OneScript (1Script). Скрипты для него пишутся на языке 1С, наличие платформы не обязательно.
Разработка рекомендована к ознакомлению и применению. Можно долго расписывать все плюсы использования скриптов. Но лучше попробовать самостоятельно написать какой-нибудь простой сценарий, чтобы войти во вкус. В качестве примера приведу свой скрипт запуска тестирования и исправления базы. Сначала производится восстановление последнего полного бэкапа SQL в тестовую базу. Затем запускается процесс ТИС, лог результата сохраняется в каталог со скриптом. Запуск скрипта можно сделать по расписанию, чтобы на начало рабочего дня иметь результат тестирования.

tis_test.os - запускаемый файл

#Использовать v8runner

БазаИсточник = "база_источник_на_SQL";
БазаПриемник = "база_приемник_на_SQL";
ПодключитьСценарий("config.os", "ПараметрыСкрипта");
ПодключитьСценарий("sql.os", "МенеджерSQL");

Параметры = Новый ПараметрыСкрипта();
МенеджерSQL = Новый МенеджерSQL();

СоединениеSQL = МенеджерSQL.ПодключитьSQL(Параметры.СерверSQL, Параметры.ПользовательSQL, 
Параметры.ПарольSQL);
Если СоединениеSQL = Неопределено Тогда
 Сообщить("Ошибка подключения к SQL.");
 ЗавершитьРаботу(1);
КонецЕсли;

Сообщить("Восставновление последнего бэкапа.");
МенеджерSQL.ВосстановитьПоследнийПолныйБэкап(СоединениеSQL, БазаИсточник, 
БазаПриемник, Параметры);

СоединениеSQL = Неопределено;

Сообщить("Запуск тестирования/исправления.");
Конфигуратор = Новый УправлениеКонфигуратором();
Конфигуратор.УстановитьКонтекст("/IBConnectionString""" + Параметры.СерверРазработки + 
"; Ref='" + БазаПриемник + "'""", Параметры.Пользователь1С, Параметры.Пароль1С);
ПараметрыЗапуска = Конфигуратор.ПолучитьПараметрыЗапуска();
ПараметрыЗапуска.Добавить("/IBCheckAndRepair -LogAndRefsIntegrity -TestOnly -BadRefNone -BadDataNone"); 

Попытка
 Конфигуратор.ВыполнитьКоманду(ПараметрыЗапуска);
Исключение
 Сообщить(Конфигуратор.ВыводКоманды());
КонецПопытки 

config.os - файл настроек

Перем СерверРазработки Экспорт;
Перем ТестоваяБаза Экспорт;
Перем Пользователь1С Экспорт;
Перем Пароль1С Экспорт;

Перем СерверSQL Экспорт;
Перем ПользовательSQL Экспорт;
Перем ПарольSQL Экспорт;
Перем КаталогФайловДанных Экспорт;
Перем КаталогФайловЖурналов Экспорт;
Перем КаталогБэкапа Экспорт;

//1С
СерверРазработки = "мой_сервер_разработки";
ТестоваяБаза = "моя_тестовая_база";
Пользователь1С = "пользователь_базы";
Пароль1С = "пароль_пользователя";
//SQL
СерверSQL = "сервер_БД";
ПользовательSQL = "пользователь";
ПарольSQL = "пароль_пользователя";
КаталогФайловДанных = "путь_к_файлам_данных";
КаталогФайловЖурналов = "путь_к_файлам_журналов";КаталогБэкапа = "путь_к_бэкапам";

sql.os - подключаемые функции для работы с SQL

Функция ПодключитьSQL(СерверSQL, ПользовательSQL, ПарольSQL) Экспорт

 Перем Command;

 СтрокаПодключения = 
 "DRIVER={SQL Server};
 |UID=" + ПользовательSQL + ";
 |Pwd=" + ПарольSQL + ";
 |Server=" + СерверSQL +";";
 
 Попытка
 
  Connection  = Новый COMОбъект("ADODB.Connection");
  Command  =   Новый COMОбъект("ADODB.Command");
  Connection.Open(СокрЛП(СтрокаПодключения));
  Command.ActiveConnection   = Connection;
  
 Исключение
  Сообщить(ОписаниеОшибки());
 КонецПопытки; 
 
 Возврат Command;

КонецФункции

Процедура СоздатьПолныйБэкап(СоединениеSQL, БазаSQL, КаталогБэкапа) Экспорт

 ТекстЗапроса = 
 "BACKUP DATABASE [" + БазаSQL + "] TO  
 |DISK = N'" + КаталогБэкапа + "\" + БазаSQL + ".bak' WITH NOFORMAT, 
 |NOINIT,  NAME = N'" + БазаSQL + " full', SKIP, NOREWIND, NOUNLOAD,  STATS = 10";
 СоединениеSQL.CommandText = ТекстЗапроса;
 СоединениеSQL.Execute();
 
КонецПроцедуры

Функция ПолучитьПоследнийФайлПолногоБэкапа(СоединениеSQL, БазаSQL) Экспорт

 Перем Результат;
 
 ТекстЗапроса = 
 "SELECT  
 |   B.physical_device_name
 |FROM 
 |   ( 
 |   SELECT   
 |    CONVERT(CHAR(100), SERVERPROPERTY('Servername')) AS Server, 
 |    msdb.dbo.backupset.database_name,  
 |    MAX(msdb.dbo.backupset.backup_finish_date) AS last_db_backup_date 
 |   FROM msdb.dbo.backupmediafamily  
 |    INNER JOIN msdb.dbo.backupset ON msdb.dbo.backupmediafamily.media_set_id = msdb.dbo.backupset.media_set_id  
 |   WHERE msdb..backupset.type = 'D' AND msdb.dbo.backupset.database_name = '" + БазаSQL + "'
 |   GROUP BY 
 |    msdb.dbo.backupset.database_name  
 |   ) AS A 
 | 
 |   LEFT JOIN  
 |
 |   ( 
 |   SELECT   
 |   CONVERT(CHAR(100), SERVERPROPERTY('Servername')) AS Server, 
 |   msdb.dbo.backupset.database_name,  
 |   msdb.dbo.backupset.backup_finish_date, 
 |   msdb.dbo.backupmediafamily.physical_device_name
 |FROM   msdb.dbo.backupmediafamily  
 |   INNER JOIN msdb.dbo.backupset ON msdb.dbo.backupmediafamily.media_set_id = msdb.dbo.backupset.media_set_id  
 |WHERE  msdb..backupset.type = 'D' AND msdb.dbo.backupset.database_name = '" + БазаSQL + "'
 |   ) AS B 
 |   ON A.[server] = B.[server] AND A.[database_name] = B.[database_name] AND A.[last_db_backup_date] = B.[backup_finish_date]";

 СоединениеSQL.CommandText = ТекстЗапроса;
 RecordSet = СоединениеSQL.Execute();
 RecordSet.MoveFirst();
 Результат = RecordSet.Fields["physical_device_name"].Value;
  
 Возврат Результат; 

КонецФункции

Процедура ВосстановитьПоследнийПолныйБэкап(СоединениеSQL, БазаSQL, ЦелеваяБазаSQL, Параметры) Экспорт

 ФайлБэкапа = ПолучитьПоследнийФайлПолногоБэкапа(СоединениеSQL, БазаSQL);
 ФайлыБазы  = ПолучитьФайлыБазы(СоединениеSQL, БазаSQL);
 ДатаСтрока = СтрРазделить(XMLСтрока(ТекущаяДата()), "T", Истина)[0];
 
 ТекстЗапроса = 
 "USE [master]
 |RESTORE DATABASE [" + ЦелеваяБазаSQL + "] FROM  DISK = N'" + ФайлБэкапа + "' WITH  FILE = 1";
 Для Каждого ФайлБазы Из ФайлыБазы Цикл
 
  Если ФайлБазы.type_desc = "ROWS" Тогда
   КаталогРазмещения = Параметры.КаталогФайловДанных;
   ПостфиксФайла = ".mdf'";
  ИначеЕсли ФайлБазы.type_desc = "LOG" Тогда
   КаталогРазмещения = Параметры.КаталогФайловЖурналов;
   ПостфиксФайла = "_log.ldf'";
  Иначе
   Сообщить("Неопределенный тип файла данных");
   ЗавершитьРаботу(1);
  КонецЕсли;
  ТекстЗапроса = ТекстЗапроса + "
  |, MOVE N'" + ФайлБазы.name + "' TO N'" + КаталогРазмещения + "\" + 
  ЦелеваяБазаSQL + "_" + ДатаСтрока + ПостфиксФайла;
  
 КонецЦикла;
 ТекстЗапроса = ТекстЗапроса + "
 |, NOUNLOAD,  REPLACE,  STATS = 5";

 СоединениеSQL.CommandText = ТекстЗапроса;
 СоединениеSQL.Execute();
 
КонецПроцедуры

Функция ПолучитьФайлыБазы(СоединениеSQL, БазаSQL) Экспорт

 Перем Результат;

 ТекстЗапроса = 
 "SELECT [file_id]
 |,[type_desc]
 |,[name]
 |,[physical_name]
 |FROM [" + БазаSQL + "].[sys].[database_files]";

 СоединениеSQL.CommandText = ТекстЗапроса;
 Результат = Новый Массив;
 RecordSet = СоединениеSQL.Execute();
 RecordSet.MoveFirst();
 
 Пока НЕ RecordSet.EOF Цикл
  Fields = RecordSet.Fields;
  СтруктураФайла = Новый Структура("name, type_desc", Fields["name"].Value, Fields["type_desc"].Value);
  Результат.Добавить(СтруктураФайла);
  RecordSet.MoveNext();
 КонецЦикла;

 Возврат Результат;

КонецФункции

Вкалывают роботы, счастлив человек :)


Комментариев нет:

Отправить комментарий