ITOP+OCS Inventory+New Class

Добрый день!
Настроил синхронизацию ITOP с OCS Inventory. Всё работает, всё понятно…
Но всё же вопрос возник:

установил класс Monitor по ссылке: Creating a new class of CI: Monitor [iTop Documentation]

добавил JSON /var/www/html/itop/extensions/ocsng-data-collector/collectors/OCSMonitorCollector.json

добавил оркестратор Orchestrator::AddCollector($iRank++, ‘OCSMonitorCollector’); в /var/www/html/itop/extensions/ocsng-data-collector/collectors/main.php

прописал класс в /var/www/html/itop/extensions/ocsng-data-collector/ocs_classes.php

добавил запрос SQL <OCSMonitorCollector_query> в /var/www/html/itop/extensions/ocsng-data-collector/conf/params.local.xml

но когда запускаю php /var/www/html/itop/extensions/ocsng-data-collector/exec.php --console_log_level=7
получаю ошибку:

[2021-09-15 11:16:06]   [Debug] Detecting if TeemIp is installed on remote iTop server
[2021-09-15 11:16:06]   [Info]  TeemIp is NOT installed on remote iTop server
[2021-09-15 11:16:06]   [Debug] OK, the required PHP version to run this application is 5.6.0. The current PHP version is 7.0.33-0+deb9u11.
[2021-09-15 11:16:06]   [Debug] OK, the required extension 'simplexml' is installed (current version: 7.0.33-0+deb9u11 >= 0.1).
[2021-09-15 11:16:06]   [Debug] OK, the required extension 'dom' is installed (current version: 20031129 >= 1.0).
[2021-09-15 11:16:06]   [Debug] The following configuration files were loaded (in this order):

        1. /var/www/html/itop/extensions/ocsng-data-collector/conf/params.distrib.xml
        2. /var/www/html/itop/extensions/ocsng-data-collector/collectors/params.distrib.xml
        3. /var/www/html/itop/extensions/ocsng-data-collector/conf/params.local.xml

The resulting configuration is:

<?xml version="1.0" encoding="UTF-8"?>
<parameters>
  <itop_url>http://itop.domain.local/itop</itop_url>
  <itop_login>admin</itop_login>
  <itop_password>password</itop_password>
  <console_log_level>6</console_log_level>
  <console_log_dateformat>[Y-m-d H:i:s]</console_log_dateformat>
  <syslog_log_level>-1</syslog_log_level>
  <data_path>%APPROOT%/data</data_path>
  <max_chunk_size>500</max_chunk_size>
  <itop_synchro_timeout>10800</itop_synchro_timeout>
  <stop_on_synchro_error>no</stop_on_synchro_error>
  <curl_options>
    <CURLOPT_SSL_VERIFYHOST>0</CURLOPT_SSL_VERIFYHOST>
    <CURLOPT_SSL_VERIFYPEER>1</CURLOPT_SSL_VERIFYPEER>
  </curl_options>
  <sql_host>ocsweb.domain.local</sql_host>
  <sql_database>ocsweb;charset=UTF8</sql_database>
  <sql_login>ocs</sql_login>
  <sql_password>password</sql_password>
  <default_org_id>company</default_org_id>
  <default_status>production</default_status>
  <PCCollection>yes</PCCollection>
  <ServerCollection>yes</ServerCollection>
  <VMCollection>yes</VMCollection>
  <collect_ips>yes</collect_ips>
  <default_ip_status>allocated</default_ip_status>
  <manage_ipv6>no</manage_ipv6>
  <default_view_name/>
  <json_placeholders>
    <prefix>OCSng</prefix>
    <full_load_interval>604800</full_load_interval>
    <synchro_status>production</synchro_status>
    <delete_policy>update</delete_policy>
    <delete_policy_update>status:obsolete</delete_policy_update>
    <delete_policy_retention>0</delete_policy_retention>
  </json_placeholders>
  <OCSBrandCollector_query>SELECT DISTINCT SMANUFACTURER as primary_key,
                SMANUFACTURER as name
                FROM bios</OCSBrandCollector_query>
  <OCSPCModelCollector_query>SELECT DISTINCT CONCAT(SMANUFACTURER,SMODEL) AS primary_key,
                SMANUFACTURER as brand_id,
                SMODEL as name,
                type,
                CASE WHEN TYPE COLLATE utf8_general_ci IN ('Notebook','LapTop','Portable') then 'Laptop' else 'PC' end  As type
                FROM bios
                        WHERE BVERSION NOT LIKE 'VMware%' AND BVERSION NOT LIKE 'VirtualBox'</OCSPCModelCollector_query>
  **<СТАНДАРТНЫЕ КОЛЛЕКЦИИ>**
  <contact_to_notify>it-support@domain.local</contact_to_notify>
  <synchro_user>OCSSync</synchro_user>
  <OCSMonitorCollector_query>
                SELECT serial AS primary_key,
                CASE WHEN manufacturer LIKE '% %' THEN CONCAT(SUBSTRING(manufacturer, 1, POSITION(" " IN manufacturer)), REPLACE(caption, 'DELL ', '')) ELSE CONCAT(manufacturer,' ', caption) END AS Name,
                manufacturer AS brand_id,
                caption AS model_id,
                description AS description,
                serial AS serialnumber,
                'Office' AS location_id,
                'LCD' AS technology
                FROM monitors
                        WHERE caption NOT LIKE 'Generic Non-PnP Monitor' AND serial is not NULL
                </OCSMonitorCollector_query>
**<СТАНДАРТНЫЕ КОЛЛЕКЦИИ>**
</parameters>

[2021-09-15 11:16:06]   [Error] Invalid Synchro Data Source definition for the collector 'OCSMonitorCollector' (not a JSON string)
[2021-09-15 11:16:06]   [Error] Exception: Cannot create Collector (invalid JSON definition)

JSON класса мониторы:

{
“name”: “$prefix$:Monitor”,
“description”: “$prefix$ Data Collector (v. $version$): Monitors”,
“status”: “$synchro_status$”,
“user_id”: “$synchro_user$”,
“notify_contact_id”: “$contact_to_notify$”,
“scope_class”: “Monitor”,
“database_table_name”: “”,
“scope_restriction”: “”,
“full_load_periodicity”: “$full_load_interval$”,
“reconciliation_policy”: “use_attributes”,
“action_on_zero”: “create”,
“action_on_one”: “update”,
“action_on_multiple”: “error”,
“delete_policy”: “$delete_policy$”,
“delete_policy_update”: “”,
“delete_policy_retention”: “0”,
“attribute_list”: [
{
“attcode”: “name”,
“update”: “1”,
“reconcile”: “1”,
“update_policy”: “master_locked”,
“finalclass”: “SynchroAttLinkSet”,
“friendlyname”: “name”
},
{
“attcode”: “description”,
“update”: “1”,
“reconcile”: “0”,
“update_policy”: “master_locked”,
“finalclass”: “SynchroAttribute”,
“friendlyname”: “description”
},
{
“attcode”: “org_id”,
“update”: “1”,
“reconcile”: “1”,
“update_policy”: “master_locked”,
“reconciliation_attcode”: “name”,
“finalclass”: “SynchroAttExtKey”,
“friendlyname”: “org_id”
},
{
“attcode”: “business_criticity”,
“update”: “0”,
“reconcile”: “0”,
“update_policy”: “master_locked”,
“finalclass”: “SynchroAttribute”,
“friendlyname”: “business_criticity”
},
{
“attcode”: “move2production”,
“update”: “0”,
“reconcile”: “0”,
“update_policy”: “master_locked”,
“finalclass”: “SynchroAttribute”,
“friendlyname”: “move2production”
},
{
“attcode”: “contacts_list”,
“update”: “0”,
“reconcile”: “0”,
“update_policy”: “master_locked”,
“row_separator”: “|”,
“attribute_separator”: “;”,
“value_separator”: “:”,
“attribute_qualifier”: “'”,
“finalclass”: “SynchroAttLinkSet”,
“friendlyname”: “contacts_list”
},
{
“attcode”: “documents_list”,
“update”: “0”,
“reconcile”: “0”,
“update_policy”: “master_locked”,
“row_separator”: “|”,
“attribute_separator”: “;”,
“value_separator”: “:”,
“attribute_qualifier”: “'”,
“finalclass”: “SynchroAttLinkSet”,
“friendlyname”: “documents_list”
},
{
“attcode”: “applicationsolution_list”,
“update”: “0”,
“reconcile”: “0”,
“update_policy”: “master_locked”,
“row_separator”: “|”,
“attribute_separator”: “;”,
“value_separator”: “:”,
“attribute_qualifier”: “'”,
“finalclass”: “SynchroAttLinkSet”,
“friendlyname”: “applicationsolution_list”
},
{
“attcode”: “providercontracts_list”,
“update”: “0”,
“reconcile”: “0”,
“update_policy”: “master_locked”,
“row_separator”: “|”,
“attribute_separator”: “;”,
“value_separator”: “:”,
“attribute_qualifier”: “'”,
“finalclass”: “SynchroAttLinkSet”,
“friendlyname”: “providercontracts_list”
},
{
“attcode”: “services_list”,
“update”: “0”,
“reconcile”: “0”,
“update_policy”: “master_locked”,
“row_separator”: “|”,
“attribute_separator”: “;”,
“value_separator”: “:”,
“attribute_qualifier”: “'”,
“finalclass”: “SynchroAttLinkSet”,
“friendlyname”: “services_list”
},
{
“attcode”: “tickets_list”,
“update”: “0”,
“reconcile”: “0”,
“update_policy”: “master_locked”,
“row_separator”: “|”,
“attribute_separator”: “;”,
“value_separator”: “:”,
“attribute_qualifier”: “'”,
“finalclass”: “SynchroAttLinkSet”,
“friendlyname”: “tickets_list”
},
{
“attcode”: “serialnumber”,
“update”: “1”,
“reconcile”: “0”,
“update_policy”: “master_locked”,
“finalclass”: “SynchroAttribute”,
“friendlyname”: “serialnumber”
},
{
“attcode”: “location_id”,
“update”: “1”,
“reconcile”: “0”,
“update_policy”: “master_locked”,
“reconciliation_attcode”: “friendlyname”,
“finalclass”: “SynchroAttExtKey”,
“friendlyname”: “location_id”
},
{
“attcode”: “status”,
“update”: “0”,
“reconcile”: “0”,
“update_policy”: “master_locked”,
“finalclass”: “SynchroAttribute”,
“friendlyname”: “status”
},
{
“attcode”: “brand_id”,
“update”: “1”,
“reconcile”: “0”,
“update_policy”: “master_locked”,
“reconciliation_attcode”: “name”,
“finalclass”: “SynchroAttExtKey”,
“friendlyname”: “brand_id”
},
{
“attcode”: “model_id”,
“update”: “1”,
“reconcile”: “0”,
“update_policy”: “master_locked”,
“reconciliation_attcode”: “”,
“finalclass”: “SynchroAttExtKey”,
“friendlyname”: “model_id”
},
{
“attcode”: “asset_number”,
“update”: “0”,
“reconcile”: “0”,
“update_policy”: “master_locked”,
“finalclass”: “SynchroAttribute”,
“friendlyname”: “asset_number”
},
{
“attcode”: “purchase_date”,
“update”: “0”,
“reconcile”: “0”,
“update_policy”: “master_locked”,
“finalclass”: “SynchroAttribute”,
“friendlyname”: “purchase_date”
},
{
“attcode”: “end_of_warranty”,
“update”: “0”,
“reconcile”: “0”,
“update_policy”: “master_locked”,
“finalclass”: “SynchroAttribute”,
“friendlyname”: “end_of_warranty”
},
{
“attcode”: “technology”,
“update”: “0”,
“reconcile”: “0”,
“update_policy”: “master_locked”,
“finalclass”: “SynchroAttribute”,
“friendlyname”: “technology”
},
{
“attcode”: “services_list”,
“update”: “0”,
“reconcile”: “0”,
“update_policy”: “master_locked”,
“row_separator”: “|”,
“attribute_separator”: “;”,
“value_separator”: “:”,
“attribute_qualifier”: “'”,
“finalclass”: “SynchroAttLinkSet”,
“friendlyname”: “services_list”
},
],
“user_delete_policy”: “administrators”,
“url_icon”: “”,
“url_application”: “”
}

Что я делаю не так?

У вас JSON в оригинале тоже с “английскими двойными” кавычками? Если нет, то https://codebeautify.org/jsonvalidator вам в помощь))

Спасибо!
Запятую лишнюю в JSON поставил (