Развертывание Экстрактора 1С централизовано по списку баз

Экстрактор 1С можно развернуть централизовано по списку баз.
Обратите внимание!

Начиная с релиза 3.10.1.28 Экстрактора 1С доступно развертывание Экстрактора 1С централизовано по списку баз. В данной статье описано автоматическое развертывание Экстрактора 1С с помощью инсталлятора версии 1.1.0.0 по списку баз с подключением к Denvic Control Center (DCC).

Также реализован сервис удаленной установки и инициализации Экстрактора в системе DCC —Extractor Manager. Подробнее о нем читайте в статье.

Параметры командной строки инсталлятора

-extractor # указывает на то что это параметры инсталлятора -cmd {command} # команда: Install, Init -result {result} # результат выполнения инсталлятора в формате: success/error + nl + msg -key {licence} # ключ лицензии -token {token} # токен оффлайн-активации # Параметры прокси, используются в том числе инсталлятором для загрузки файлов -proxytype {proxytype} # Пусто - не изменяется, 0 - Не используется; 1 - По умолчанию; 2 - Настройка, см. параметры ниже; -proxyprotocol {proxyprotocol} # http, https, ftp, ftps -proxyserver {proxyserver}-proxyport {proxyport} -proxyuser {proxyuser} -proxypass {proxypass} -proxyos {proxyos} -dir {directory} # директория с установочными файлами -ver {version} # версия модуля в формате "3.9.1.54" # Параметры rest api dcc-dcc_addr {dcc_addr} -dcc_login {dcc_login} -dcc_pass {dcc_pass} -dcc_timeout {dcc_timeout} -dcc_id {dcc_id} # Идентификатор в DCC - выполнить обновление, пусто - не выполнять регистрацию, auto - выполнить регистрацию или обновление -dcc_name {dcc_name} # Наименование в DCC, пусто - не изменяется, auto - формируется инсталлятором из наименования предприятия (Константы.ЗаголовокСистемы) # Параметры планировщика заданий обмена с DCC -dcc_scheduler {dcc_scheduler} # on - включить обмен, off (любое отличное от "on") - выключить обмен, при пустом значении текущее состояние не изменится -dcc_scheduler_retry_interval {dcc_scheduler_retry_interval} # интервал повтора при аварийном завершении -dcc_scheduler_retry_count {dcc_scheduler_retry_count} # Количество повторов при аварийном завершении -dcc_scheduler_user {dcc_scheduler_user} # Пользователь от имени которого выполняется обмен: auto = Текущий пользователь, пусто = пользователь будет подбираться системой автоматически (останется не заполненным) -dcc_scheduler_time_start {dcc_scheduler_time_start} # Время запуска обмена в формате HH:mm -dcc_scheduler_interval {dcc_scheduler_interval} # Интервал запуска обмена, секунды # Параметры планировщика заданий обмена с DCC метаданными конфигурации 1С # Описание см. параметры обмена -dcc_meta_scheduler {dcc_meta_scheduler} -dcc_meta_scheduler_retry_interval {dcc_meta_scheduler_retry_interval} -dcc_meta_scheduler_retry_count {dcc_meta_scheduler_retry_count} -dcc_meta_scheduler_user {dcc_meta_scheduler_user} -dcc_meta_scheduler_time_start {dcc_meta_scheduler_time_start} -dcc_meta_scheduler_interval {dcc_meta_scheduler_interval}

Пример запуска инсталлятора из командной строки

Путь к инсталлятору указывается в ключе /Execute.
Параметры указываются в ключе /C.

Обратите внимание!

Кавычки в параметрах должны быть удвоены, если параметр содержит пробелы, то он должен быть в кавычках и кавычки в кавычках еще удваиваются.

"C:\Program Files\1cv8\8.3.23.2157\bin\1cv8.exe" ENTERPRISE /IBConnectionString "File=""E:\TEST BASE\DEV-BATCH 1"";" /N "Администратор" /P "123!@#$%^&*""'" /AppAutoCheckVersion /Execute"\\srv-1c-03\exchange\batch\Инсталлятор.epf" /C" -extractor -cmd Init -result ""\\srv-1c-03\exchange\batch\6fcb8d13-5b56-4697-a383-e5af26ef1734"" -key ""11011442011068772636052"" -token """" -dcc_id auto -dcc_name ""Тест №1"" -dcc_login ""admin"" -dcc_pass admin_pass -dcc_addr http://10.101.9.108:8080/api -dcc_timeout 30 -dcc_scheduler on -dcc_scheduler_retry_interval 30 -dcc_scheduler_retry_count 2 -dcc_scheduler_user auto -dcc_scheduler_interval 60 -dcc_meta_scheduler_retry_interval 60 -dcc_meta_scheduler_retry_count 2 -dcc_meta_scheduler_user auto -dcc_meta_scheduler_time_start 01:00 -dcc_meta_scheduler_interval 0"

Пример пакетного разворачивания инсталлятора на Python

Настройки задаются в файле config.yaml. Пример текста такого файла:

# константы auto: &auto _auto_ # Лицензия licence: "" # номер лицензии token: "" # токен # Устанавливаемая версия version: *auto # auto или версия в формате "3.9.1.54". auto = версия определяется по загруженным файлам, см. files # каталог с файлами установки, если нужного файла нет, то он будет загружен в этот каталог files: \\srv-1c-03\exchange\batch\files # файл результатов result: \\srv-1c-03\exchange\batch\result # Параметры прокси, используются в том числе инсталлятором для загрузки файлов proxytype: # Пусто - не изменяется, 0 - Не используется; 1 - По умолчанию; 2 - Настройка, см. параметры ниже; proxyprotocol: # http, https, ftp, ftps proxyserver: proxyport: proxyuser: proxypass: # Параметры rest api DCC dcc_addr: # адрес dcc_login: # логин dcc_pass: # пароль dcc_timeout: 30 # Параметры рег. задания обмена с DCC dcc_scheduler: "on" # on - включить обмен, off (любое отличное от "on") - выключить, при пустом значении текущее состояние не изменится dcc_scheduler_retry_interval: 30 # интервал повтора при аварийном завершении dcc_scheduler_retry_count: 2 # Количество повторов при аварийном завершении dcc_scheduler_user: &dcc_scheduler_user _auto_ # Пользователь от имени которого выполняется РЗ: auto = Текущий пользователь; пустое = пользователь будет подбираться системой автоматически (останется не заполненным) dcc_scheduler_time_start: # Время запуска рег задания, HH:mm dcc_scheduler_interval: 60 # Таймаут запуска рег задания, секунды # Параметры рег задания обмена с DCC метаданными конфигурации 1С # Описание см. рег задание обмена dcc_meta_scheduler: dcc_meta_scheduler_retry_interval: 60 dcc_meta_scheduler_retry_count: 2 dcc_meta_scheduler_user: &dcc_meta_scheduler_user _auto_ dcc_meta_scheduler_time_start: "01:00" dcc_meta_scheduler_interval: 0 path1c: C:\Program Files\1cv8\%platform%\bin\1cv8.exe # путь до исполняемого файла platform: &platform 8.3.23.2157 # версия платформы подставляется в path1c, переопределяется в bases.platform dcc_group: &dcc_group # Наименование группы DCC, переопределяется в bases.dcc_group bases: - enabled: True connect: Srvr="1";Ref="1"; # Строка подключения 1С, где после Srvr= вместо 1 необходимо указать кластер серверов, а после Ref= - имя информационной базы user: "" # имя пользователя password: "" # пароль учетной записи пользователя platform: *platform # версия платформы подставляется в path1c dcc_group: *dcc_group # Наименование группы DCC dcc_id: *auto # Идентификатор в DCC, пусто - не выполнять регистрацию или _auto_ - для необходимости выполнить регистрацию, если не заполнено dcc_name: "Отладочная автотесты New(29.12.2025)" # Наименование в DCC, пусто - не изменяется, _auto_ - формируется инсталлятором из наименования предприятия (Константы.ЗаголовокСистемы) dcc_scheduler_user: *dcc_scheduler_user dcc_meta_scheduler_user: *dcc_meta_scheduler_user - enabled: True connect: Srvr="2";Ref="2"; # Строка подключения 1С, где после Srvr= вместо 2 необходимо указать кластер серверов, а после Ref= - имя информационной базы user: "" # имя пользователя password: "" # пароль учетной записи пользователя platform: *platform dcc_group: *dcc_group dcc_id: *auto dcc_name: *auto dcc_scheduler_user: *dcc_scheduler_user dcc_meta_scheduler_user: *dcc_meta_scheduler_user - enabled: True connect: Srvr="3";Ref="3"; # Строка подключения 1С, где после Srvr= вместо 3 необходимо указать кластер серверов, а после Ref= - имя информационной базы user: "" # имя пользователя password: "" # пароль учетной записи пользователя platform: *platform dcc_group: *dcc_group dcc_id: *auto dcc_name: "Пакетная установка тест ERP 2.5 + Datalens" dcc_scheduler_user: *dcc_scheduler_user dcc_meta_scheduler_user: *dcc_meta_scheduler_user

Листинг кода:

import sys import os import uuid import yaml import argparse import re import subprocess from pprint import pprint #from xml.etree import ElementTree #import datetime #import shutil #import uuid #import json #import requests # #import psycopg2 #from pygit2 import Repository #import boto3 ############################################################## def main(): #sys.stdout.reconfigure(encoding='utf-8') parser = argparse.ArgumentParser(prog='Extractor1C batch installer', description='Extractor1C batch installer', usage='batch.py [options]') parser.add_argument('-cmd', '--command', type=str, help='Команда: Install, Init', required=True) parser.add_argument('-i', '--installer', type=str, help='Путь к списку баз', required=True) parser.add_argument('-c', '--config', type=str, help='Путь к файлу настроек', required=True) parser.add_argument('-f', '--filter', type=str, help='Путь к фильтру баз', required=False) args = parser.parse_args() print("\n####################\n") pprint(args) installer_path = args.installer; config_path = args.config; command = args.command; commands = [item.strip() for item in command.split(',')] pprint(commands) if not os.path.isabs(installer_path): installer_path = os.path.abspath(installer_path) if not os.path.isabs(config_path): config_path = os.path.abspath(config_path) with open(config_path, 'r', encoding='utf-8') as file: config = yaml.safe_load(file) print("\n####################\n") pprint(config) installation_files = config["files"]; results_file = config["result"] licence = config["licence"] token = config["token"] path1c_template = config["path1c"] version = config["version"] # создадим каталог для файлов инсталлятора if not os.path.exists(installation_files): os.makedirs(installation_files) # определим версию if version == "_auto_" or version is None: for item in os.listdir(installation_files): print(item) refind = re.search("\(\d+_\d+_\d+_\d+\)", item) if refind: version = refind.group(0).replace("_", ".")[1:-1] print("\n####################\n") pprint("Версия = " + version) if version == "_auto_" or version is None: print(f"Укажите версию или загрузите файлы в '{installation_files}'") return # файл для результата инсталлятора directory = os.path.dirname(results_file) result_install = os.path.join(directory, str(uuid.uuid4())) for base in config["bases"]: if not base["enabled"]: continue path1c = path1c_template.replace("%platform%", base["platform"]) connection_string = base["connect"] user1c = '/N "' + base["user"].replace('"', '""') + '"' if base["user"] else "" pass1c = '/P "' + base["password"].replace('"', '""') + '"' if user1c and base["password"] else "" connection_string_replaced = connection_string.replace('"', '""') cmd_template = f'"{path1c}" ENTERPRISE /IBConnectionString "{connection_string_replaced}" {user1c} {pass1c} /AppAutoCheckVersion /Execute"{installer_path}"' for command in commands: params = [] params.append('-extractor') params.append(f'-cmd {command}') params.append(f'-result ""{result_install}""') params.append(f'-key ""{licence}""') params.append(f'-token ""{token}""') if config.get("proxytype") is not None: params.append(f'-proxytype {config["proxytype"]}') if config.get("proxyprotocol") is not None: params.append(f'-proxyprotocol {config["proxyprotocol"]}') if config.get("proxyserver") is not None: params.append(f'-proxyserver {config["proxyserver"]}') if config.get("proxyport") is not None: params.append(f'-proxyport {config["proxyport"]}') if config.get("proxyuser") is not None: params.append(f'-proxyuser {config["proxyuser"]}') if config.get("proxypass") is not None: params.append(f'-proxypass {config["proxypass"]}') if config.get("proxyos") is not None: params.append(f'-proxyos {config["proxyos"]}') if command == "Install": params.append(f'-dir ""{installation_files}""') params.append(f'-ver {version}') elif command == "Init": if base.get("dcc_id") is not None: params.append(f'-dcc_id {base["dcc_id"]}') if base.get("dcc_name") is not None: params.append(f'-dcc_name ""{base["dcc_name"]}""') if config.get("dcc_login") is not None: params.append('-dcc_login ""' + config["dcc_login"].replace('"', '""') + '""') if config.get("dcc_pass") is not None: params.append(f'-dcc_pass {config["dcc_pass"]}') if config.get("dcc_addr") is not None: params.append(f'-dcc_addr {config["dcc_addr"]}') if config.get("dcc_timeout")is not None: params.append(f'-dcc_timeout {config["dcc_timeout"]}') if config.get("dcc_scheduler") is not None: params.append(f'-dcc_scheduler {config["dcc_scheduler"]}') if config.get("dcc_scheduler_retry_interval") is not None: params.append(f'-dcc_scheduler_retry_interval {config["dcc_scheduler_retry_interval"]}') if config.get("dcc_scheduler_retry_count") is not None: params.append(f'-dcc_scheduler_retry_count {config["dcc_scheduler_retry_count"]}') if config.get("dcc_scheduler_user") is not None: params.append(f'-dcc_scheduler_user {base["dcc_scheduler_user"]}') if config.get("dcc_scheduler_time_start") is not None: params.append(f'-dcc_scheduler_time_start {config["dcc_scheduler_time_start"]}') if config.get("dcc_scheduler_interval") is not None: params.append(f'-dcc_scheduler_interval {config["dcc_scheduler_interval"]}') if config.get("dcc_meta_scheduler") is not None: params.append(f'-dcc_meta_scheduler {config["dcc_meta_scheduler"]}') if config.get("dcc_meta_scheduler_retry_interval") is not None: params.append(f'-dcc_meta_scheduler_retry_interval {config["dcc_meta_scheduler_retry_interval"]}') if config.get("dcc_meta_scheduler_retry_count") is not None: params.append(f'-dcc_meta_scheduler_retry_count {config["dcc_meta_scheduler_retry_count"]}') if config.get("dcc_meta_scheduler_user") is not None: params.append(f'-dcc_meta_scheduler_user {config["dcc_meta_scheduler_user"]}') if config.get("dcc_meta_scheduler_time_start") is not None: params.append(f'-dcc_meta_scheduler_time_start {config["dcc_meta_scheduler_time_start"]}') if config.get("dcc_meta_scheduler_interval") is not None: params.append(f'-dcc_meta_scheduler_interval {config["dcc_meta_scheduler_interval"]}') params_string = ' '.join(params) cmd = cmd_template + f' /C"{params_string}"' result = execute_cmd(cmd, result_install) print("\n####################\n") print(result) if result["status"] == "error": break append_to_file(results_file, connection_string + "\t" + result["status"] + "\t" + result["msg"]) ############################################################## def execute_cmd(cmd, result_install): print("\n####################\n") print(cmd) #result_cmd = os.system(cmd) err_msg = "" try: result = subprocess.run(cmd, capture_output=True, text=True, check=True, timeout=300) #print("STDOUT:", result.stdout) #print("STDERR:", result.stderr) except subprocess.CalledProcessError as e: err_msg = f"Команда завершена с кодом ошибки {e.returncode}" except subprocess.TimeoutExpired as e: err_msg = f"Превышен таймаут выполнения команды {e.timeout} секунд" except FileNotFoundError: err_msg = f"Команда не найдена" except Exception as e: err_msg = f"Ошибка выполнения команды: {e}" if err_msg: result = { "status": "error", "msg": err_msg } else: if os.path.isfile(result_install): with open(result_install, 'r', encoding='utf-8-sig') as file: flines = file.read().splitlines() #os.remove(result_install) flines_count = len(flines) pprint(flines) if flines_count == 0: result = { "status": "error", "msg": "Результат не известен. Файл результата пустой" } else: result = { "status": flines[0], "msg": flines[1] } else: result = { "status": "error", "msg": "Результат не известен. Отсутствует файл результата" } return result ############################################################## def append_to_file(path, text): with open(path, 'a') as file: file.write(text + "\n") ############################################################## main()

Вариант запуска выглядит следующим образом:

py "E:\Batch\batch.py" -cmd "Install, Init" -i "\\srv-1c-03\exchange\batch\Инсталлятор.epf" -c "E:\Batch\config.yaml"