def get_content_error(self, content): """ Проверка возвращаемого значение/содержания на ошибки. @param content: Возвращаемое значение какой либо операции. @return: Текст ошибки, None - нет ошибки. """ if content is None: msg = u'Не определено содержание для проверки на ошибки' log.warning(msg) journal.write_msg(msg) return None if 'A' not in content: msg = u'Не корректный формат <%s>' % content log.warning(msg) journal.write_msg(msg) return None if 'error' in content['A']: err_txt = content['A']['error'] # Отобразить контент для отладки msg = u'Ошибка содержимого: <%s>' % content log.error(msg) journal.write_msg(msg) return err_txt return None
def print_context(self, context): """ Вывести в консоль внутренне состояние объекта источника данных. Функция сделана для отладки. """ log.debug(u'Состояние контекста <%s>.<%s>' % (self.__class__.__name__, self.name)) log.debug(u'\t[Переменная]\t\t[Значение]') for name, val in context.items(): try: val_codepage = strfunc.get_codepage(val) if isinstance( val, str) else txtgen.DEFAULT_ENCODING if val_codepage is None: val_codepage = txtgen.DEFAULT_ENCODING val = unicode( str(val), val_codepage) if not isinstance(val, unicode) else val log.debug(u'\t<%s>\t\t<%s>' % (name, val)) except UnicodeDecodeError: log.error(u'Ошибка отображения состояния переменной <%s>' % name) except UnicodeEncodeError: log.error(u'Ошибка отображения состояния переменной <%s>' % name)
def create_src(self, **properties): """ Метод создания объекта источника данных с инициализацией его свойств. @param properties: Словарь свойств источника данных. @return: Объект источника данных или None в случае ошибки. """ # Сначала в любом случае определяем тип источника данных if 'type' in properties: src_typename = properties['type'] src_class = src.DATA_SOURCES.get(src_typename, None) if src_class is None: log.error( u'Ошибка создания объекта источника данных. Тип <%s> не зарегистрирован в системе как источник данных' % src_typename) else: try: log.info(u'Создание объекта источника данных <%s>' % properties.get('name', src_class.__name__)) src_obj = src_class(parent=self, **properties) # Регистрируем новый объект в словаре внутренних объектов self.reg_object(src_obj) return src_obj except: log.fatal(u'Ошибка создания объекта источника данных') else: name = properties.get('name', u'') log.error( u'Ошибка создания объекта источника данных. Не определен тип <%s>' % name) return None
def create(self, **properties): """ Создание объекта. По значениям свойств функция сама определяет какого типа будет объект. @param properties: Словарь свойств объекта. @return: Объект приемника данных или None в случае ошибки. """ name = properties.get('name', u'') # Сначала определяем тип объекта if 'type' in properties: type_name = properties['type'] else: log.error(u'Ошибка создания объекта. Не определен тип <%s>' % name) return None # Сначала проверяем является ли объект источником данных if type_name in src.DATA_SOURCES: return self.create_src(**properties) # Сначала проверяем является ли объект источником данных if type_name in dst.DATA_DESTINATIONS: return self.create_dst(**properties) log.warning( u'Тип <%s> объекта <%s> не зарегистрирован среди источнико или приемников данных' % (type_name, name)) return None
def get_xml_content_by_link(xml_content, link): """ Получить часть содержимого XML файла по пути. @param xml_content: Сродержимое XML файла. @param link: Запрашиваемый путь. Может быть представлен в виде списка или строки. Например: root/Documents/1/Document/Title/value @return: Часть содержимого или None если по этому пути ничего не найдено. """ log.debug(u'Получение содержимого XML файла по пути %s' % link) if type(link) in (str, unicode): link = link.split(XML_CONTENT_LINK_DELIMETER) if type(link) not in (list, tuple): log.error(u'Не корректный тип пути <%s> до содержимого XML файла' % type(link)) return None if not link: return xml_content if link[0] not in xml_content: log.warning(u'Не найден путь %s в содержимом %s XML файла' % (link, xml_content.keys())) return None elif link[0] in xml_content: return get_xml_content_by_link(xml_content[link[0]], link[1:]) return None
def load_xml_content(xml_filename, is_change_keys=True): """ Загрузить содержимое XML файла в словарно списковую структуру. @param xml_filename: Полное имя XML файла. @param is_change_keys: Произвести автоматическую замену ключей на короткие. @return: Словарно-списковая структура содержания XML файла. Или None в случае ошибки. """ if not os.path.exists(xml_filename): log.warning(u'XML файл <%s> не найден' % xml_filename) return None log.info(u'Загрузка содержимого файла <%s>' % xml_filename) xml_file = None try: xml_file = open(xml_filename, 'r') xml_txt = xml_file.read() xml_file.close() except: if xml_file: xml_file.close() log.fatal(u'Ошибка загрузки содержимого XML файла <%s>' % xml_filename) return None if not xml_txt.strip(): log.error(u'Файл <%s> пустой' % xml_filename) return dict() data = xmltodict.parse(xml_txt) if is_change_keys: data = change_keys_doc(data) return data
def create_connection(self, host=None): """ Создание объекта связи с UniReader XMLRPC сервером. @param host: Хост OPC сервера для возможности удаленного подключения (через DCOM) к OPC серверу. Если не определен, то считается что OPC сервер находится локально. @return: Объект Uni - сервера. """ if type(host) not in (None.__class__, str, unicode): msg = u'UniReader. Не корректный тип хоста OPC сервера <%s>' % type( host) log.error(msg) journal.write_msg(msg) return None is_local_opc = (host is None) or (type(host) in (str, unicode) and host.lower().strip() in ('localhost', '127.0.0.1')) if is_local_opc: log.info(u'UniReader. OPC сервер находится локально') else: log.info(u'UniReader. OPC сервер находится на <%s>' % host) url = UNI_SERVER_URL_FMT % (host, self.uni_port) log.info(u'UniReader. URL для подключения к Uni-серверу: <%s>' % url) connection = xmlrpclib.ServerProxy(url) return connection
def uninstall(*argv): """ Главноя функция запуска деинсталляции. В качестве ключей могут быть параметры деинсталляции. [Параметры] --debug - включить все сервисы в режиме отладки --log - включить все сервисы в режиме журналирования --dialog - включить режим диалогов pythondialogs --urwid - включить режим диалогов urwid (по умолчанию) --check= - отметить секцию для установки --uncheck= - снять отметку секции для установки """ log.init(config) log.info(config.TITLE_TXT) try: from .ic.cui import install_wizard except Exception: from ic.cui import install_wizard # Разбираем аргументы командной строки try: options, args = getopt.getopt(argv, 'DL', ['debug', 'log', 'dialog', 'urwid', 'check=', 'uncheck=']) except getopt.error as msg: log.error(u'Ошибка параметров коммандной строки %s' % str(msg), bForcePrint=True) log.warning(__doc__, bForcePrint=True) sys.exit(2) programms = copy.deepcopy(config.UNINSTALL_PROGRAMM) for option, arg in options: if option in ('--debug', '-D'): utils.set_var('SERVICES_DEBUG_MODE', True) log.info(u'Деинсталяция. Установка режима отладки') elif option in ('--log', '-L'): utils.set_var('SERVICES_LOG_MODE', True) log.info('Деинсталяция. Установка режима журналирования') elif option in ('--dialog', ): utils.set_var('DIALOG_MODE', 'python-dialog') elif option in ('--urwid', ): utils.set_var('DIALOG_MODE', 'urwid') elif option in ('--check',): section = int(arg) if arg.isdigit() else arg programms = util.check_section(programms, section, True) elif option in ('--uncheck',): section = int(arg) if arg.isdigit() else arg programms = util.check_section(programms, section, False) result = install_wizard.uninstall(dProgramms=programms) log.info(config.TITLE_TXT) return result
def get_http(self, url): """ Получить содержание по URL. @param url: Адрес запроса. @return: Вовращает содержимое XML файла или None в случае ошибки. """ if not (url.startswith('http://') or url.startswith('https://')): log.warning( u'Указан не абсолютный адрес <%s> при получении содержания по адресу' % url) url = self.utm_url + url log.info(u'Преобразуем адрес к абсолютному виду <%s>' % url) try: output_xml_filename = os.path.join(self.output_dir, DEFAULT_OUTPUT_XML_FILENAME) if os.path.exists(output_xml_filename): try: log.info(u'Удаление файла <%s>' % output_xml_filename) os.remove(output_xml_filename) except: msg = u'Ошибка удаления файла <%s>' % output_xml_filename log.fatal(msg) journal.write_msg(msg) cmd = '"%s" --output "%s" -X GET %s' % (self.curl, output_xml_filename, url) execfunc.exec_shell(cmd) content = None if os.path.exists(output_xml_filename): try: content = xmlfunc.load_xml_content(output_xml_filename) except: msg = u'Ошибка XML файла данных <%s>' % output_xml_filename log.error(msg) journal.write_msg(msg) self._backup_error_file(output_xml_filename) raise else: msg = u'Не найден выходной файл УТМ <%s>' % output_xml_filename log.warning(msg) journal.write_msg(msg) return content except: msg = u'Ошибка получения содержания УТМ по адресу <%s>' % url log.fatal(msg) journal.write_msg(msg) return None
def diagnostic(self): """ Простая процедура прверки доступа к источнику данных. @return: True/False. """ connection = None log.info(u'UniReader. Диагностика <%s>.<%s>' % (self.__class__.__name__, self.name)) if self.opc_server is None: msg = u'UniReader. Не определен OPC сервер в <%s>' % self.name log.warning(msg) journal.write_msg(msg) return False if self.topic is None: msg = u'UniReader. Не определен топик в <%s>' % self.name log.warning(msg) journal.write_msg(msg) return False try: # Создание клиента OPC connection = self.create_connection(self.uni_host) if connection is None: msg = u'Не возможно создать объект связи с UniReader. Хост <%s>' % self.uni_host log.error(msg) journal.write_msg(msg) return None # Контроль наличия процедуры чтения значений из OPC сервера rpc_methods = connection.system.listMethods() if 'sources.ReadValueAsString' not in rpc_methods: msg = u'UniReader. Процедура чтения значения из OPC сервера не найдена. Хост <%s>' % self.uni_host log.error(msg) journal.write_msg(msg) return None else: log.info(u'UniReader. Список методов удаленного вызова %s' % str(rpc_methods)) return True except: msg = u'UniReader. Ошибка диагностики <%s>' % self.__class__.__name__ log.fatal(msg) journal.write_msg(msg) return False
def _del_package_path(self, sPackagePath): """ Удаление инсталляционной папки пакета физически. @param sPackagePath: Инсталляционная папка/файл пакета. @return: True-все ок, False-удаление не произошло по какой-то причине. """ try: if not sPackagePath: return False path=os.path.normpath(sPackagePath) if os.path.exists(path): shutil.rmtree(path, 1) return True return False except: log.error(u'Ошибка удаления директории <%s>' % sPackagePath) raise
def _read_value(self, address): """ Прочитать значение по адресу из RSLinx. @param address: Адрес. Адрес задается явно. @return: Прочитанное значение либо None в случае ошибки. """ opc = None try: # Создание клиента OPC opc = self.create_opc_client(self.opc_host) if opc is None: msg = u'Не возможно создать объект клиента OPC. Хост <%s>' % self.opc_host log.error(msg) journal.write_msg(msg) return None # Список серверов OPC servers = opc.servers() if self.opc_server not in servers: msg = u'Сервер <%s> не найден среди %s' % (self.opc_server, servers) log.warning(msg) journal.write_msg(msg) opc.close() return None # Соедиенение с сервером server = self.opc_server opc.connect(server) # Прочитать из OPC сервера val = opc.read(address) result = self.recode(val[0]) if val and val[1] == 'Good' else None opc.close() log.debug(u'Адрес <%s>. Результат чтения данных %s' % (address, result)) return result except: if opc: opc.close() msg = u'Ошибка чтения значения по адресу <%s> в <%s>' % (address, self.__class__.__name__) log.fatal(msg) journal.write_msg(msg) return None
def gen_correct_value(self, value, cur_state=None): """ Генерация значения с учетом порядка блоков кодов и ссылок. @param value: Генерируемое значение. @param cur_state: Текущее состояние объекта. @return: Признак произведенной замены, Сгенерированное значение. """ if cur_state is None: cur_state = dict([(name, getattr(self, name)) for name in self.values]) if txtgen.is_genered(value): replace_names = txtgen.get_raplace_names(value) replaces = dict() for name in replace_names: if name not in cur_state: log.error( u'Переменная <%s> не определена в описании объекта <%s>' % (name, self.name)) continue is_fill, replaces[name] = self.gen_correct_value( cur_state[name], cur_state) log.debug(u'\tЗамена <%s> => <%s> => <%s>' % (name, cur_state[name], replaces[name])) value = txtgen.gen(value, replaces) if self.parent.is_link(value): # Это просто ссылка без требования генерации value = self.parent.get_value_by_link(value) elif execfunc.is_code_python(value) or execfunc.is_code_func( value): # Это просто блок кода без требования генерации value = execfunc.exec_code_block(value) return True, value elif self.parent.is_link(value) and not txtgen.is_genered(value): # Это просто ссылка без требования генерации return True, self.parent.get_value_by_link(value) elif (execfunc.is_code_python(value) or execfunc.is_code_func(value)) and not txtgen.is_genered(value): # Это просто блок кода без требования генерации return True, execfunc.exec_code_block(value) return False, value
def create_opc_client(self, opc_host=None): """ Создание объекта OPC клиента. @param opc_host: Хост OPC сервера для возможности удаленного подключения (через DCOM) к OPC серверу. Если не определен, то считается что OPC сервер находится локально. @return: Объект OPC сервера. """ if type(opc_host) not in (None.__class__, str, unicode): msg = u'Не корректный тип хоста OPC сервера <%s>' % type(opc_host) log.error(msg) journal.write_msg(msg) return None is_local_opc = (opc_host is None) or (type(opc_host) in (str, unicode) and opc_host.lower().strip() in ('localhost', '127.0.0.1')) if is_local_opc: log.info(u'OPC сервер находится локально') opc = OpenOPC.client() else: log.info(u'OPC сервер находится на <%s>' % opc_host) opc = OpenOPC.open_client(opc_host) return opc
def _read_value(self, address): """ Прочитать значение по адресу из OPC сервера. @param address: Адрес. Адрес задается явно. @return: Прочитанное значение либо None в случае ошибки. """ connection = None try: # Создание связи connection = self.create_connection(self.uni_host) if connection is None: msg = u'Не возможно создать объект связи с UniReader. Хост <%s>' % self.uni_host log.error(msg) journal.write_msg(msg) return None # Контроль наличия процедуры чтения значений из OPC сервера rpc_methods = connection.system.listMethods() if 'sources.ReadValueAsString' not in rpc_methods: msg = u'UniReader. Процедура чтения значения из OPC сервера не найдена. Хост <%s>' % self.uni_host log.error(msg) journal.write_msg(msg) return None # Прочитать из OPC сервера val = connection.sources.ReadValueAsString('OPC_SERVER_NODE', self.opc_server, address) result = self.recode(val[0]) if val else None log.debug(u'UniReader. Адрес <%s>. Результат чтения данных %s' % (address, result)) return result except: msg = u'UniReader. Ошибка чтения значения по адресу <%s> в <%s>' % ( address, self.__class__.__name__) log.fatal(msg) journal.write_msg(msg) return None
def valid_content(self, content): """ Анализ содержания на ошибки. @param content: Содержание в текстовом виде. """ if CURL_HTTP_404_ERR in content: msg = u'Http 404' log.error(msg) log.error(content) journal.write_msg(msg) return None elif CURL_HTTP_500_ERR in content: msg = u'Http 500' log.error(msg) log.error(content) journal.write_msg(msg) return None return content
def diagnostic(self): """ Простая процедура прверки доступа к источнику данных. @return: True/False. """ opc = None log.info(u'Диагностика <%s>.<%s>' % (self.__class__.__name__, self.name)) if self.opc_server is None: msg = u'Не определен OPC сервер в <%s>' % self.name log.warning(msg) journal.write_msg(msg) return False if self.topic is None: msg = u'Не определен топик в <%s>' % self.name log.warning(msg) journal.write_msg(msg) return False try: # Создание клиента OPC opc = self.create_opc_client(self.opc_host) if opc is None: msg = u'Не возможно создать объект клиента OPC. Хост <%s>' % self.opc_host log.error(msg) journal.write_msg(msg) return None # Список серверов OPC servers = opc.servers() if self.opc_server not in servers: msg = u'Сервер <%s> не найден среди %s' % (self.opc_server, servers) log.warning(msg) journal.write_msg(msg) opc.close() return False server = self.opc_server log.info(u'Диагностика OPC сервера <%s>' % server) # Соедиенение с сервером opc.connect(server) # Вывод состояния сервера log.info(u'Общая информация о OPC сервере') info_list = opc.info() for inf in info_list: log.info(u'\t%s' % str(inf)) # Список интерфейсов servers topics = opc.list() if self.topic not in topics: msg = u'Топик <%s> не найден среди %s' % (self.topic, topics) log.warning(msg) journal.write_msg(msg) opc.close() return False # Режимы одного топика topic = topics[topics.index(self.topic)] log.info(u'Топик/Интерфейс: %s' % topic) modes = opc.list(topic) log.info(u'\tРежимы: %s' % modes) # Переменные for mode in modes: address = topic+u'.'+mode tags = opc.list(address) log.info(u'\t\tТеги <%s>:' % address) for tag in tags: log.info(u'\t\t\t%s' % tag) # Закрытие соединения opc.close() return True except: if opc: opc.close() msg = u'Ошибка диагностики <%s>' % self.__class__.__name__ log.fatal(msg) journal.write_msg(msg) return False
def _read(self, *values): """ Чтение данных из источника данных. @param values: Список читаемых переменных. @return: Список прочитанных значений. Если переменная не найдена или произошла ошибка чтения, то вместо значения подставляется None с указанием WARNING в журнале сообщений. """ connection = None if not values: log.warning( u'UniReader. Не определены переменные для чтения в <%s>' % self.name) values = self.addresses log.debug( u'UniReader. Переменные взяты из описания источника данных: %s' % values) try: # Создание клиента OPC connection = self.create_connection(self.uni_host) if connection is None: msg = u'Не возможно создать объект связи с UniReader. Хост <%s>' % self.uni_host log.error(msg) journal.write_msg(msg) return None # Контроль наличия процедуры чтения значений из OPC сервера rpc_methods = connection.system.listMethods() if 'sources.ReadValueAsString' not in rpc_methods: msg = u'UniReader. Процедура чтения значения из OPC сервера не найдена. Хост <%s>' % self.uni_host log.error(msg) journal.write_msg(msg) return None # Подготовка переменных для чтения # Адреса всегда задаются строками addresses = self._gen_addresses(*values) log.debug(u'UniReader. Чтение адресов %s' % addresses) # Прочитать из OPC сервера result = list() for address in addresses: value = connection.sources.ReadValueAsString( 'OPC_SERVER_NODE', self.opc_server, address) result.append(self.recode(value) if value else None) # Регистрация состояния state = dict([(values[i], val) for i, val in enumerate(result)]) self.reg_state(**state) log.debug(u'UniReader. Результат чтения данных:') for i, value in enumerate(result): log.debug(u'\t%s\t=\t%s' % (addresses[i], value)) return result except: msg = u'UniReader. Ошибка чтения данных <%s>' % self.__class__.__name__ log.fatal(msg) journal.write_msg(msg) return None
def main(*argv): """ Главноя функция запуска инсталляции. В качестве ключей могут быть параметры инсталяции. [Параметры] --debug - включить все сервисы в режиме отладки --log - включить все сервисы в режиме журналирования --dialog - включить режим диалогов pythondialogs --urwid - включить режим диалогов urwid (по умолчанию) --dosemu_dir= - папка инсталляции dosemu --icservices_dir= - папка инсталляции icservices --check= - отметить секцию для установки --uncheck= - снять отметку секции для установки """ log.init(config) log.info(config.TITLE_TXT) # Проверка устанувки библиотеки pythondialog if not util.check_python_library_version('dialog'): from . import packages packages.install_pythondialog() # Проверка на устанвки библиотеки urwid if not util.check_python_library_version('urwid'): from . import packages packages.install_urwid() try: from .ic.cui import install_wizard except Exception: from ic.cui import install_wizard # Разбираем аргументы командной строки try: options, args = getopt.getopt(argv, 'DL', [ 'debug', 'log', 'dialog', 'urwid', 'dosemu_dir=', 'icservices_dir=', 'check=', 'uncheck=' ]) except getopt.error as err: log.error(u'Ошибка параметров коммандной строки %s' % err.msg, bForcePrint=True) log.warning(__doc__, bForcePrint=True) sys.exit(2) for option, arg in options: if option in ('--debug', '-D'): utils.set_var('SERVICES_DEBUG_MODE', True) log.info(u'Инсталяция. Установка режима отладки') elif option in ('--log', '-L'): utils.set_var('SERVICES_LOG_MODE', True) log.info(u'Инсталяция. Установка режима журналирования') elif option in ('--dialog', ): utils.set_var('DIALOG_MODE', 'python-dialog') elif option in ('--urwid', ): utils.set_var('DIALOG_MODE', 'urwid') elif option in ('--dosemu_dir', ): config.PROGRAMM[config.DRIVE_C_SECTION]['dir'] = arg log.info(u'Dosemu директория <%s>' % config.PROGRAMM[config.DRIVE_C_SECTION]['dir']) elif option in ('--icservices_dir', ): config.PROGRAMM[config.ICSERVICES_SECTION]['dir'] = arg log.info(u'icservices директория <%s>' % config.PROGRAMM[config.ICSERVICES_SECTION]['dir']) config.PROGRAMM[config.ICDAEMON_SECTION]['dir'] = arg log.info(u'icdaemon директория <%s>' % config.PROGRAMM[config.ICDAEMON_SECTION]['dir']) elif option in ('--check', ): section = int(arg) if arg.isdigit() else arg config.PROGRAMM = util.check_section(config.PROGRAMM, section, True) elif option in ('--uncheck', ): section = int(arg) if arg.isdigit() else arg config.PROGRAMM = util.check_section(config.PROGRAMM, section, False) result = install_wizard.install(install_script, None, None) log.info(config.TITLE_TXT) return result
def _read(self, *values): """ Чтение данных из источника данных. @param values: Список читаемых переменных. @return: Список прочитанных значений. Если переменная не найдена или произошла ошибка чтения, то вместо значения подставляется None с указанием WARNING в журнале сообщений. """ opc = None if not values: log.warning(u'Не определены переменные для чтения в <%s>' % self.name) values = self.addresses log.debug(u'Переменные взяты из описания источника данных: %s' % values) try: # Создание клиента OPC opc = self.create_opc_client(self.opc_host) if opc is None: msg = u'Не возможно создать объект клиента OPC. Хост <%s>' % self.opc_host log.error(msg) journal.write_msg(msg) return None # Список серверов OPC servers = opc.servers() if self.opc_server not in servers: msg = u'Сервер <%s> не найден среди %s' % (self.opc_server, servers) log.warning(msg) journal.write_msg(msg) opc.close() return None # Соедиенение с сервером server = self.opc_server opc.connect(server) # Подготовка переменных для чтения # Адреса всегда задаются строками addresses = self._gen_addresses(*values) log.debug(u'Чтение адресов %s' % addresses) # Прочитать из OPC сервера result = [self.recode(val[1]) if val and val[2] == 'Good' else None for val in opc.read(addresses)] # result = [val.encode('') if isinstance(val, unicode) else val for val in result] # result = [val for val in opc.read(addresses)] opc.close() # Регистрация состояния state = dict([(values[i], val) for i, val in enumerate(result)]) self.reg_state(**state) log.debug(u'Результат чтения данных %s' % result) return result except: if opc: opc.close() msg = u'Ошибка чтения данных <%s>' % self.__class__.__name__ log.fatal(msg) journal.write_msg(msg) return None