Ejemplo n.º 1
0
    def _write(self, *values):
        """
        Записать данные в приемник данных.
        @param values: Список записываемых значений
        @return: True/False.
        """
        if self.template_fmt is None:
            msg = u'Не указан шаблон для заполнения форматированного текстового файла.'
            log.warning(msg)
            journal.write_msg(msg)
            return False

        if self.output_fmt is None:
            msg = u'Не указан выходной файл для заполнения форматированного текстового файла.'
            log.warning(msg)
            journal.write_msg(msg)
            return False

        context = self.get_values_as_dict()
        template = txtgen.gen(self.template_fmt, context)
        output = txtgen.gen(self.output_fmt, context)

        # Заполняем шаблон переменными
        gen_result = txtgen.gen_txt_file(template, output, context)
        return gen_result
Ejemplo n.º 2
0
    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
Ejemplo n.º 3
0
    def get_xml_filenames(self):
        """
        Определить список обрабатываемых XML файлов.
        @return: Cписок обрабатываемых XML файлов.
        """
        if self.cache_xml_filenames:
            # Работаем с мгновенным слепком списка файлов
            return self.cache_xml_filenames

        if self.xml_filename is None:
            msg = u'Не определены XML файлы источника данных <%s>' % self.__class__.__name__
            log.warning(msg)
            journal.write_msg(msg)
            return list()

        xml_filenames = list()
        if self.is_filename_pattern(self.xml_filename):
            # Если это шаблон, то получить список файлов
            xml_filenames = glob.glob(self.xml_filename)

            log.info(u'Найдены XML файлы в <%s>:' % self.xml_filename)
            for xml_filename in xml_filenames:
                log.info(u'\t%s' % xml_filename)

        # Это указание конкретного файла
        if os.path.exists(self.xml_filename):
            self.cache_xml_filenames = [self.xml_filename]
            return self.cache_xml_filenames
        # else:
        #     log.warning(u'Не найден XML файл <%s> источника данных' % self.xml_filename)
        self.cache_xml_filenames = xml_filenames
        return self.cache_xml_filenames
Ejemplo n.º 4
0
    def parse_inbox_docs(self,
                         doc_uuids=None,
                         str_replaces=None,
                         **content_links):
        """
        Произвести сборку данных входных документов по запрашиваемым данным.
        @param doc_uuids: Список UUID необходимых входных документов.
            Если None, то обрабатываются все документы.
        @param str_replaces: Словарь замены в строковых значениях.
            Если словарь не определен замены не производятся.
        @param content_links: Словарь запрашиваемых данных у каждого документа.
            Например:
            {
                'error': 'A/error',
                'transport_uuid': 'A/url'
            }
        @return: Список заполненных словарей запрашиваемых данных для каждого документа.
        """
        if doc_uuids is None:
            doc_uuids = self.get_inbox_doc_uuid()

        result = list()
        for doc_uuid in doc_uuids:
            if not doc_uuid:
                msg = u'УТМ. Не корректный UUID запрашиваемого документа <%s>' % doc_uuid
                log.warning(msg)
                journal.write_msg(msg)
                continue
            doc = self.parse_inbox_doc(doc_uuid,
                                       str_replaces=str_replaces,
                                       **content_links)
            if doc is not None:
                result.append(doc)
        log.debug(u'УТМ. Сборка данных входных документов %s' % result)
        return result
Ejemplo n.º 5
0
    def gen_sql_code(self, code):
        """
        Дополнение кода информацией из контекста описания объекта.
        ВНИМАНИЕ! Т.к. одинарные кавычки не должны присутствовать,
        то необходимо сделать дополнительную предобработку контекста.
        @param code: Строка блока кода.
        @return: Полностью заполненная и готовая к выполнению строка блока кода.
        """
        if not code:
            return None

        if self.cache_state is None:
            self.cache_state = self.fill_state()
        context = self.get_context(self.cache_state)

        # ВНИМАНИЕ! Т.к. одинарные кавычки не должны присутствовать,
        # то необходимо сделать дополнительную предобработку контекста.
        for name, value in context.items():
            # context[name] = str(value).replace('\'', '"')
            if type(value) in (str, unicode):
                try:
                    context[name] = value.replace('\'', '"')
                except UnicodeEncodeError:
                    msg = u'Ошибка замены кавычек в значении <%s>' % value
                    log.fatal(msg)
                    journal.write_msg(msg)
        result = self.gen_code(code, context)
        return result
Ejemplo n.º 6
0
    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
Ejemplo n.º 7
0
    def _read(self, *values):
        """
        Чтение данных из источника данных.
        @param values: Список читаемых переменных.
        @return: Список прочианных значений.
            Если переменная не найдена или произошла ошибка чтения, то
            вместо значения подставляется None с указанием WARNING в журнале сообщений.
        """
        xml_filenames = self.get_xml_filenames()

        if not values:
            log.warning(u'Не определены переменные для чтения в <%s>' %
                        self.name)
            values = self.values
            log.debug(u'Переменные взяты из описания источника данных: %s' %
                      values)

        try:
            result = [list() for i in range(len(values))]
            for xml_filename in xml_filenames:
                # Получаем содержимое XML файла
                xml_content = xmlfunc.load_xml_content(xml_filename)
                for i, value in enumerate(values):
                    value_path = getattr(self, value)
                    xml_value = xmlfunc.get_xml_content_by_link(
                        xml_content, value_path)
                    result[i].append(xml_value)

            # Регистрация состояния
            state = dict([(values[i], val) for i, val in enumerate(result)])
            self.reg_state(**state)

            if self.auto_remove:
                for xml_filename in xml_filenames:
                    if os.path.exists(xml_filename):
                        try:
                            log.info(u'Удаление файла <%s>' % xml_filename)
                            os.remove(xml_filename)
                        except:
                            msg = u'Ошибка удаления файла <%s>' % xml_filename
                            log.fatal(msg)
                            journal.write_msg(msg)

            return result
        except:
            log.fatal(u'Ошибка чтения данных из файлов %s' % xml_filenames)

        return None
Ejemplo n.º 8
0
    def find_inbox_document(self, doc_uuid):
        """
        Найти входящий документ по его UUID.
        @param doc_uuid: UUID документа.
        @return: Словарь содержимого документа или None если документ не найден или ошибка.
        """
        if self.cache_state and INBOX_STATE_NAME in self.cache_state:
            if doc_uuid in self.cache_state[INBOX_STATE_NAME]:
                return self.cache_state[INBOX_STATE_NAME][doc_uuid]
            else:
                msg = u'Кеш источника данных <%s>. Документ <%s> не найден во входящих' % (
                    self.name, doc_uuid)
                log.warning(msg)
                journal.write_msg(msg)
        else:
            content = self.get_http('/opt/out')
            if content:
                document_urls = content['A'].get('url', list())
                if type(document_urls) not in (list, tuple):
                    # ВНИМАНИЕ! Может быть только 1 документ
                    # Все равно мы должны обрабатывать список
                    document_urls = [document_urls]

                if not document_urls:
                    msg = u'Список входящих документов пуст'
                    log.warning(msg)
                    journal.write_msg(msg)

                for document_url in document_urls:
                    if isinstance(
                            document_url,
                            dict) and document_url['@replyId'] == doc_uuid:
                        document_content = self.get_http(document_url['#text'])

                        # ВНИМАНИЕ! Необходимо кроме содержания запоминать URL и ReplyID документа
                        # иначе нельзя будет идентифицировать документ
                        # return document_content
                        return dict(url=document_url['#text'],
                                    uuid=doc_uuid,
                                    content=document_content)
                    elif isinstance(document_url, str) or isinstance(
                            document_url, unicode):
                        # Внимание! Если документ имеет родительский документ - то есть и replyId,
                        # если документ первичный - то и нет для него replyId
                        # Т.е. не правильно ого искать по UUID
                        log.warning(
                            u'Поиск. Внешний первичный документ <%s> пропущен'
                            % document_url)
                        continue
                msg = u'Документ <%s> не найден во входящих' % doc_uuid
                log.warning(msg)
                journal.write_msg(msg)
            else:
                msg = u'Нет ответа от УТМ'
                log.warning(msg)
                journal.write_msg(msg)
        return None
Ejemplo n.º 9
0
 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
Ejemplo n.º 10
0
    def del_http(self, url):
        """
        Удалит данные по URL на сервере УТМ.
        Когда ответ на запрос обработан его необходимо удалить
        командой вида:
        curl -X DELETE http://localhost:8080/opt/out/ReplyPartner/407
        Регулярное удаление отработанных запросов из списка и сохраненных ответов
        на эти запросы из списка предотвращает безконтрольный рост размера
        базы данных УТМ.
        @param url: Адрес запроса.
        """
        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 DELETE %s' % (
                self.curl, output_xml_filename, url)
            execfunc.exec_shell(cmd)

            content = xmlfunc.load_xml_content(output_xml_filename)
            if content is not None:
                # Необходимо проанализировать ошибки
                content = self.valid_content(content)
                return content
        except:
            msg = u'Ошибка удаления данных УТМ по адресу <%s>' % url
            log.fatal(msg)
            journal.write_msg(msg)
        return None
Ejemplo n.º 11
0
    def disconnect(self, connection=None):
        """
        Разорвать соединение с БД.
        @param connection: Объект связи с БД.
        @return: True/False.
        """
        if connection is None:
            connection = self.connection

        if connection:
            connection.dispose()
            if connection == self.connection:
                self.connection = None
            connection = None
            return True
        else:
            msg = u'Не определен объект связи с БД в <%s>' % self.name
            log.warning(msg)
            journal.write_msg(msg)
        return False
Ejemplo n.º 12
0
    def write(self, *values):
        """
        Записать данные в приемник данных.
        Функция выполняется с пред... и пост... обработкой.
        @param values: Список записываемых значений
        @return: True/False.
        """
        if self.all_values:
            # Необходимо провести проверку на заполнение всех значений
            if not self.valid_all_values(*values):
                msg = u'Не полностью заполнены входные значения для генерации файла <%s>' % str(self.output_fmt)
                log.warning(msg)
                journal.write_msg(msg)
                return False

        # Перед выполнение произвести замену из контекста
        return execfunc.exec_prev_post_decorate(self._write,
                                                self.gen_code(self.prev_cmd),
                                                self.gen_code(self.post_cmd),
                                                *values)
Ejemplo n.º 13
0
    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
Ejemplo n.º 14
0
    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
Ejemplo n.º 15
0
 def _backup_error_file(self, src_filename, err_filename=None):
     """
     Сохранить ошибочный файл в папке.
     @param src_filename: Имя исходного ошибочного файла.
     @param err_filename: Имя нового файла.
         Если не определено, то имя генерируется по времени.
     @return: True/False.
     """
     if err_filename is None:
         err_filename = os.path.join(
             str(self.output_dir),
             datetime.datetime.now().strftime('%Y_%m_%d_%H_%M_%S.err'))
     try:
         if os.path.exists(err_filename):
             os.remove(err_filename)
         shutil.copyfile(src_filename, err_filename)
         return True
     except:
         msg = u'Ошибка сохранения ошибочного файла'
         log.fatal(msg)
         journal.write_msg(msg)
     return False
Ejemplo n.º 16
0
    def _read(self, *values):
        """
        Чтение данных из источника данных.
        @param values: Список читаемых переменных.
        @return: Список прочианных значений.
            Если переменная не найдена или произошла ошибка чтения, то
            вместо значения подставляется None с указанием WARNING в журнале сообщений.
        """
        if not values:
            log.warning(u'Не определены переменные для чтения в <%s>' %
                        self.name)
            values = self.values
            log.debug(u'Переменные взяты из описания источника данных: %s' %
                      values)

        try:
            # Прочитать все документы
            inbox_docs = self.get_inbox_documents()
            if inbox_docs is None:
                return False

            # Регистрация состояния
            if not self.cache_state:
                inbox = dict([(doc.get('uuid', str(uuid.uuid4())), doc)
                              for doc in inbox_docs])
                state = dict([(val, self.gen_code(getattr(self, val)))
                              for val in values])
                # state = self.get_values_as_dict(values)
                state[INBOX_STATE_NAME] = inbox
                self.reg_state(**state)

                self.cache_state = self.state

            return inbox_docs
        except:
            msg = u'Ошибка чтения входящих документов УТМ'
            log.fatal(msg)
            journal.write_msg(msg)
        return None
Ejemplo n.º 17
0
    def connect(self, db_url=None):
        """
        Соединение с БД.
        @param db_url: Конекшн стринг подключения к БД.
        @return: Объект sqlalchemy движка.
        """
        if db_url is None:
            db_url = self.get_db_url()

        if self.connection:
            self.disconnect()
            self.connection = None
        try:
            # Отображение в консоли выполняемых SQL выражений---------+
            #                                                         V
            self.connection = sqlalchemy.create_engine(db_url, echo=False)
        except:
            msg = u'Ошибка соединения с БД <%s>' % db_url
            log.fatal(msg)
            journal.write_msg(msg)
            self.connection = None
        return self.connection
Ejemplo n.º 18
0
    def _read(self, *values):
        """
        Прочитать данные из источника данных.
        @param values: Список получаемых значений.
        @return: Список имен файлов.
        """
        if not self.filename_pattern:
            msg = u'Не определен шаблон поиска файлов'
            log.warning(msg)
            journal.write_msg(msg)
            return list()

        filenames = glob.glob(self.filename_pattern)

        log.info(u'Найденные файлы:')
        for filename in filenames:
            log.info(u'\t%s' % filename)

        self.state = dict([(os.path.basename(filename),
                            os.path.abspath(filename))
                           for filename in filenames])
        return filenames
Ejemplo n.º 19
0
    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
Ejemplo n.º 20
0
    def parse_inbox_doc(self, doc_uuid, str_replaces=None, **content_links):
        """
        Произвести сборку данных входных документов по запрашиваемым данным.
        @param doc_uuid: UUID необходимого входного документа.
        @param str_replaces: Словарь замены в строковых значениях.
            Если словарь не определен замены не производятся.
        @param content_links: Словарь запрашиваемых данных у каждого документа.
            Например:
            {
                'error': 'A/error',
                'transport_uuid': 'A/url'
            }
        @return: Список заполненных словарей запрашиваемых данных для документа.
        """
        if doc_uuid is None:
            msg = u'УТМ. Не определен UUID документа при запросе данных'
            log.warning(msg)
            journal.write_msg(msg)
            return dict([(name, None) for name in content_links.keys()])

        doc_content = self.find_inbox_document(doc_uuid)
        if doc_content:
            result = dict()
            for name, link in content_links.items():
                value = xmlfunc.get_xml_content_by_link(doc_content, link)
                if str_replaces and type(value) in (str, unicode):
                    for replace_src, replace_dst in str_replaces.items():
                        value = value.replace(replace_src, replace_dst)
                result[name] = value
            return result
        else:
            msg = u'УТМ. Ошибка чтения содержимого документа <%s>' % doc_uuid
            log.warning(msg)
            journal.write_msg(msg)

        return None
Ejemplo n.º 21
0
    def _write(self, *values):
        """
        Записать данные в приемник данных.
        @param values: Список записываемых значений
        @return: True/False.
        """
        if not self.sql:
            msg = u'Не определено SQL выражение для записи данных в <%s>' % self.name
            log.warning(msg)
            journal.write_msg(msg)
            return False

        sql = self.gen_sql_code(self.sql)
        if sql is None:
            msg = u'Ошибка запроса SQL'
            log.warning(msg)
            journal.write_msg(msg)
            return False

        if not sql.strip():
            msg = u'Попытка выполнения пустого запроса SQL'
            log.warning(msg)
            journal.write_msg(msg)
            return False

        try:
            self.connect()
            log.info(u'Выполнение SQL: <%s>' % sql)
            self.connection.execute(sql)
            self.disconnect()
            return True
        except:
            self.disconnect()
            msg = u'Ошибка записи данных в <%s>' % self.name
            log.fatal(msg)
            journal.write_msg(msg)
        return False
Ejemplo n.º 22
0
    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
Ejemplo n.º 23
0
    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
Ejemplo n.º 24
0
    def _read(self, *values):
        """
        Прочитать данные из источника данных.
        @param values: Список получаемых значений.
        @return: Список записей/рекордсет.
        """
        self.recordset = list()
        if not self.sql:
            msg = u'Не определено SQL выражение для получения данных в <%s>' % self.name
            log.warning(msg)
            journal.write_msg(msg)
            self.reg_state(recordset=self.recordset)
            return self.recordset

        sql = self.gen_sql_code(self.sql)
        if not sql.strip():
            msg = u'Попытка выполнения пустого запроса SQL'
            log.warning(msg)
            journal.write_msg(msg)
            self.reg_state(recordset=self.recordset)
            return self.recordset

        try:
            self.connect()
            log.info(u'Выполнение SQL: <%s>' % sql)
            recordset = self.connection.execute(sql)
            self.disconnect()
            self.recordset = [dict(rec) for rec in recordset]
            log.debug(u'Результат запроса: %s' % str(self.recordset))
        except:
            self.disconnect()
            msg = u'Ошибка получения данных в <%s>' % self.name
            log.fatal(msg)
            journal.write_msg(msg)
            self.recordset = list()
        self.reg_state(recordset=self.recordset)
        return self.recordset
Ejemplo n.º 25
0
    def get_inbox_documents(self):
        """
        Запросить входящие документы.
        """
        if self.cache_state and INBOX_STATE_NAME in self.cache_state:
            return self.cache_state[INBOX_STATE_NAME].values()

        content = self.get_http('/opt/out')
        if content is None:
            msg = u'Ошибка определения данных по адресу </opt/out>'
            log.warning(msg)
            journal.write_msg(msg)
            return None

        if not self.get_content_error(content):
            documents = list()
            if 'A' not in content:
                # Если не ссылка на документ, то это просто его содержание
                documents.append(
                    dict(url=u'', uuid=str(uuid.uuid4()), content=content))
            else:
                document_urls = content['A'].get('url', list())
                if type(document_urls) not in (list, tuple):
                    # ВНИМАНИЕ! Может быть только 1 документ
                    # Все равно мы должны обрабатывать список
                    document_urls = [document_urls]

                if not document_urls:
                    msg = u'Список входящих документов ЕГАИС УТМ пуст'
                    log.warning(msg)
                    journal.write_msg(msg)
                    return documents
                else:
                    #
                    log.debug(u'Обрабатываемые документы. URLs:')
                    for document_url in document_urls:
                        log.debug(u'\t%s' % document_url)

                for document_url in document_urls:
                    if isinstance(document_url, str) or isinstance(
                            document_url, unicode):
                        log.debug(u'Получаем документ URL (str) <%s>' %
                                  document_url)
                        document_content = self.get_http(document_url)
                        documents.append(
                            dict(url=document_url,
                                 uuid=str(uuid.uuid4()),
                                 content=document_content))
                    elif isinstance(document_url, dict):
                        log.debug(u'Получаем документ URL (dict) <%s>' %
                                  document_url['#text'])
                        document_content = self.get_http(document_url['#text'])
                        documents.append(
                            dict(url=document_url['#text'],
                                 uuid=document_url['@replyId'],
                                 content=document_content))
                    else:
                        msg = u'Не обрабатываемый тип адреса документа <%s>' % document_url
                        log.warning(msg)
                        journal.write_msg(msg)

            return documents
        else:
            return None
Ejemplo n.º 26
0
    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
Ejemplo n.º 27
0
    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
Ejemplo n.º 28
0
    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
Ejemplo n.º 29
0
    def run_tick(self, n_tick=1):
        """
        Запуск всех объектов для выполнения 1 тика.
        @param n_tick: Номер текущего тика.
        @return: True/False.
        """
        try:
            config.set_cfg_var('TICK_DT_START', datetime.datetime.now())
            # ВНИМАНИЕ! Необходимо с начале каждого тика надо создавать объекты
            # чтобы не контролировать актуальность их состояния
            log.info(u'Создание объектов...')
            src_objects = list()
            for properties in config.SOURCES:
                # Создаем объекты источников данных
                obj = self.create(**properties)
                if obj:
                    src_objects.append(obj)
            dst_objects = list()
            for properties in config.DESTINATIONS:
                # Создаем объекты получателей данных
                obj = self.create(**properties)
                if obj:
                    dst_objects.append(obj)

            if not config.QUEUE:
                log.info(u'Порядок обработки штатный')
                log.info(u'Начало обработки...')
                journal.write_msg(u'Начало обработки...')
                for src_object in src_objects:
                    log.info(u'Чтение данных из <%s>' % src_object.name)
                    journal.write_msg(u'\tЧтение данных из <%s>' %
                                      src_object.description)
                    src_object.read_as_dict()
                for dst_object in dst_objects:
                    log.info(u'Запись данных в <%s>' % dst_object.name)
                    journal.write_msg(u'\tЗапись данных в <%s>' %
                                      dst_object.description)
                    dst_object.write_as_dict()
                log.info(u'...Конец обработки [%d]' % n_tick)
                journal.write_msg(u'...Конец обработки')
            else:
                log.info(u'Порядок обработки задан явно %s' % config.QUEUE)
                log.info(u'Начало обработки...')
                journal.write_msg(u'Начало обработки...')
                for obj_properties in config.QUEUE:
                    obj_name = obj_properties['name']
                    obj = self.find_object(obj_name)
                    if obj:
                        obj_type = obj_properties['type']
                        if obj_type in src.DATA_SOURCES.keys():
                            # Это источник данных
                            log.info(u'Чтение данных из <%s>' % obj.name)
                            journal.write_msg(u'\tЧтение данных из <%s>' %
                                              obj.description)
                            obj.read_as_dict()
                        elif obj_type in dst.DATA_DESTINATIONS.keys():
                            # Это получатель данных
                            log.info(u'Запись данных в <%s>' % obj.name)
                            journal.write_msg(u'\tЗапись данных в <%s>' %
                                              obj.description)
                            obj.write_as_dict()
                        else:
                            # Вообще не определенный тип
                            log.warning(
                                u'Не поддерживаемый тип <%s> объекта <%s>' %
                                (obj_type, obj_name))
                log.info(u'...Конец обработки [%d]' % n_tick)
                journal.write_msg(u'...Конец обработки')

            # Сбросить кеш состояния в конце такта
            # obj_list = src_objects + dst_objects
            # self.clear_all_state_chaches(*obj_list)
            return True
        except:
            log.fatal(u'Ошибка выполнения тика [%d]' % n_tick)
        return False